home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / javax / swing / JTree.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  145.1 KB  |  4,202 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)JTree.java    1.78 98/05/11
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package javax.swing;
  16.  
  17. import java.awt.*;
  18. import java.awt.event.*;
  19. import java.beans.*;
  20. import java.io.*;
  21. import java.util.*;
  22. import javax.swing.event.*;
  23. import javax.swing.plaf.TreeUI;
  24. import javax.swing.tree.*;
  25. import javax.accessibility.*;
  26.  
  27.  
  28. /**
  29.  * A control that displays a set of hierarchical data as an outline.
  30.  * A specific node can be identified either by a TreePath (an object
  31.  * that encapsulates a node and all of its ancestors), or by its
  32.  * display row, where each row in the display area displays one node.
  33.  * <p>
  34.  * An <i>expanded</i> node is one displays its children. A <i>collapsed</i>
  35.  * node is one which hides them. A <i>hidden</i> node is one which is
  36.  * under a collapsed parent. A <i>viewable</i> node is under a collapsed 
  37.  * parent, but may or may not be displayed. A <i>displayed</i> node
  38.  * is both viewable and in the display area, where it can be seen.
  39.  * <p>
  40.  * These JTree methods use "visible" to mean "displayed":<ul>
  41.  * <li><code>isRootVisible()</code>
  42.  * <li><code>setRootVisible()</code>
  43.  * <li><code>scrollPathToVisible()</code>
  44.  * <li><code>scrollRowToVisible()</code>
  45.  * <li><code>getVisibleRowCount()</code>
  46.  * <li><code>setVisibleRowCount()</code>
  47.  * </ul>
  48.  * <p>
  49.  * These JTree methods use "visible" to mean "viewable" (under an
  50.  * expanded parent):<ul>
  51.  * <li><code>isVisible()</code>
  52.  * <li><code>makeVisible()</code>
  53.  * </ul>
  54.  * <p>
  55.  * If you are interested in knowing when the selection changes implement
  56.  * the TreeSelectionListener interface and add the instance using the
  57.  * method addTreeSelectionListener. valueChanged will be invoked when the
  58.  * selection changes, that is if the user clicks twice on the same
  59.  * node valueChanged will only be invoked once.
  60.  * <p>
  61.  * If you are interested in knowing either double clicks events or when
  62.  * a user clicks on a node, regardless of whether or not it was selected
  63.  * it is recommended you do the following:
  64.  * <pre>
  65.  * final JTree tree = ...;
  66.  *
  67.  * MouseListener ml = new MouseAdapter() {
  68.  *     public void <b>mouseClicked</b>(MouseEvent e) {
  69.  *         int selRow = tree.getRowForLocation(e.getX(), e.getY());
  70.  *         TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
  71.  *         if(selRow != -1) {
  72.  *             if(e.getClickCount() == 1) {
  73.  *                 mySingleClick(selRow, selPath);
  74.  *             }
  75.  *             else if(e.getClickCount() == 2) {
  76.  *                 myDoubleClick(selRow, selPath);
  77.  *             }
  78.  *         }
  79.  *     }
  80.  * };
  81.  * tree.addMouseListener(ml);
  82.  * </pre>
  83.  * NOTE: This example obtains both the path and row, but you only need to
  84.  * get the one you're interested in.
  85.  * <p>
  86.  * To use JTree to display compound nodes (for example, nodes containing both
  87.  * a graphic icon and text), subclass {@link TreeCellRenderer} and use 
  88.  * {@link #setTreeCellRenderer} to tell the tree to use it. To edit such nodes,
  89.  * subclass {@link TreeCellEditor} and use {@link #setTreeCellEditor}.
  90.  * <p>
  91.  * Like all JComponent classes, you can use {@link JComponent#registerKeyboardAction}
  92.  * to associate an {@link Action} object with a {@link KeyStroke} and execute the
  93.  * action under specified conditions.
  94.  * <p>
  95.  * See <a href="http://java.sun.com/docs/books/tutorial/ui/swing/tree.html">How to Use Trees</a>
  96.  * in <a href="http://java.sun.com/Series/Tutorial/index.html"><em>The Java Tutorial</em></a>
  97.  * for further documentation.
  98.  * <p>
  99.  * For the keyboard keys used by this component in the standard Look and
  100.  * Feel (L&F) renditions, see the
  101.  * <a href="doc-files/Key-Index.html#JTree">JTree</a> key assignments.
  102.  * <p>
  103.  * <strong>Warning:</strong>
  104.  * Serialized objects of this class will not be compatible with
  105.  * future Swing releases.  The current serialization support is appropriate
  106.  * for short term storage or RMI between applications running the same
  107.  * version of Swing.  A future release of Swing will provide support for
  108.  * long term persistence.
  109.  *
  110.  * @beaninfo
  111.  *   attribute: isContainer false
  112.  *
  113.  * @version 1.78 05/11/98
  114.  * @author Rob Davis
  115.  * @author Ray Ryan
  116.  * @author Scott Violet
  117.  */
  118. public class JTree extends JComponent implements Scrollable, Accessible
  119. {
  120.     /**
  121.      * @see #getUIClassID
  122.      * @see #readObject
  123.      */
  124.     private static final String uiClassID = "TreeUI";
  125.  
  126.     /**
  127.      * The model that defines the tree displayed by this object.
  128.      */
  129.     transient protected TreeModel        treeModel;
  130.  
  131.     /**
  132.      * Models the set of selected nodes in this tree.
  133.      */
  134.     transient protected TreeSelectionModel selectionModel;
  135.  
  136.     /**
  137.      * True if the root node is displayed, false if its children are
  138.      * the highest visible nodes.
  139.      */
  140.     protected boolean                    rootVisible;
  141.  
  142.     /**
  143.      * The cell used to draw nodes. If null, the UI uses a default
  144.      * cellRenderer.
  145.      */
  146.     transient protected TreeCellRenderer  cellRenderer;
  147.  
  148.     /**
  149.      * Height to use for each display row. If this is <= 0 the renderer 
  150.      * determines the height for each row.
  151.      */
  152.     protected int                         rowHeight;
  153.  
  154.     /**
  155.      * Maps from TreePath to Boolean indicating whether or not the
  156.      * pareticular path is expanded. This ONLY indicates whether a 
  157.      * given path is expanded, and NOT if it is visible or not. That
  158.      * information must be determined by visiting all the parent
  159.      * paths and seeing if they are visible.
  160.      */
  161.     transient private Hashtable           expandedState;
  162.  
  163.  
  164.     /**
  165.      * True if handles are displayed at the topmost level of the tree.
  166.      * <p>
  167.      * A handle is a small icon that displays adjacent to the node which 
  168.      * allows the user to click once to expand or collapse the node. A
  169.      * common interface shows a plus sign (+) for a node which can be
  170.      * expanded and a minus sign (-) for a node which can be collapsed.
  171.      * Handles are always shown for nodes below the topmost level.
  172.      * <p>
  173.      * If the <code>rootVisible</code> setting specifies that the root 
  174.      * node is to be displayed, then that is the only node at the topmost
  175.      * level. If the root node is not displayed, then all of its 
  176.      * children are at the topmost level of the tree. Handles are 
  177.      * always displayed for nodes other than the topmost.
  178.      * <p> 
  179.      * If the root node isn't visible, it is generally a good to make 
  180.      * this value true. Otherwise, the tree looks exactly like a list,
  181.      * and users may not know that the "list entries" are actually
  182.      * tree nodes.
  183.      *
  184.      * @see #rootVisible
  185.      */
  186.     protected boolean           showsRootHandles;
  187.  
  188.     /**
  189.      * Creates a new event and passed it off the selectionListeners.
  190.      */
  191.     protected transient TreeSelectionRedirector selectionRedirector;
  192.  
  193.     /**
  194.      * Editor for the entries.  Default is null (tree is not editable).
  195.      */
  196.     transient protected TreeCellEditor          cellEditor;
  197.  
  198.     /**
  199.      * Is the tree editable? Default is false.
  200.      */
  201.     protected boolean                 editable;
  202.  
  203.     /**
  204.      * Is this tree a large model? This is a code-optimization setting.
  205.      * A large model can be used when the cell height is the same for all
  206.      * nodes. The UI will then cache very little information and instead
  207.      * continually message the model. Without a large model the UI caches 
  208.      * most of the information, resulting in fewer method calls to the model.
  209.      * <p>
  210.      * This value is only a suggestion to the UI. Not all UIs will
  211.      * take advantage of it. Default value is false.
  212.      */
  213.     protected boolean                 largeModel;
  214.  
  215.     /**
  216.      * Number of rows to make visible at one time. This value is used for
  217.      * the Scrollable interface. It determines the preferred size of the 
  218.      * display area.
  219.      */
  220.     protected int                     visibleRowCount;
  221.  
  222.     /**
  223.      * If true, when editing is to be stopped by way of selection changing,
  224.      * data in tree changing or other means stopCellEditing is invoked, and
  225.      * changes are saved. If false, cancelCellEditing is invoked, and changes
  226.      * are discarded. Default is false.
  227.      */
  228.     protected boolean                 invokesStopCellEditing;
  229.  
  230.     /**
  231.      * If true, when a node is expanded, as many of the descendants are 
  232.      * scrolled to be visible.
  233.      */
  234.     protected boolean                 scrollsOnExpand;
  235.  
  236.     /**
  237.      * Number of mouse clicks before a node is expanded.
  238.      */
  239.     protected int                     toggleClickCount;
  240.  
  241.     /**
  242.      * Updates the expandedState.
  243.      */
  244.     transient protected TreeModelListener       treeModelListener;
  245.  
  246.     /**
  247.      * Used when setExpandedState is invoked, will be a Stack of Stacks.
  248.      */
  249.     transient private Stack           expandedStack;
  250.  
  251.     /**
  252.      * Max number of stacks to keep around.
  253.      */
  254.     private static int                TEMP_STACK_SIZE = 11;
  255.  
  256.     //
  257.     // Bound propery names
  258.     //
  259.     /** Bound property name for cellRenderer. */
  260.     public final static String        CELL_RENDERER_PROPERTY = "cellRenderer";
  261.     /** Bound property name for treeModel. */
  262.     public final static String        TREE_MODEL_PROPERTY = "treeModel";
  263.     /** Bound property name for rootVisible. */
  264.     public final static String        ROOT_VISIBLE_PROPERTY = "rootVisible";
  265.     /** Bound property name for showsRootHandles. */
  266.     public final static String        SHOWS_ROOT_HANDLES_PROPERTY = "showsRootHandles";
  267.     /** Bound property name for rowHeight. */
  268.     public final static String        ROW_HEIGHT_PROPERTY = "rowHeight";
  269.     /** Bound property name for cellEditor. */
  270.     public final static String        CELL_EDITOR_PROPERTY = "cellEditor";
  271.     /** Bound property name for editable. */
  272.     public final static String        EDITABLE_PROPERTY = "editable";
  273.     /** Bound property name for largeModel. */
  274.     public final static String        LARGE_MODEL_PROPERTY = "largeModel";
  275.     /** Bound property name for selectionModel. */
  276.     public final static String        SELECTION_MODEL_PROPERTY = "selectionModel";
  277.     /** Bound property name for visibleRowCount. */
  278.     public final static String        VISIBLE_ROW_COUNT_PROPERTY = "visibleRowCount";
  279.     /** Bound property name for messagesStopCellEditing. */
  280.     public final static String        INVOKES_STOP_CELL_EDITING_PROPERTY = "messagesStopCellEditing";
  281.     /** Bound property name for scrollsOnExpand. */
  282.     public final static String        SCROLLS_ON_EXPAND_PROPERTY = "scrollsOnExpand";
  283.     /** Bound property name for toggleClickCount. */
  284.     //public final static String        TOGGLE_CLICK_COUNT_PROPERTY = "toggleClickCount";
  285.  
  286.  
  287.     /**
  288.      * Creates and returns a sample TreeModel. Used primarily for beanbuilders.
  289.      * to show something interesting.
  290.      *
  291.      * @return the default TreeModel
  292.      */
  293.     protected static TreeModel getDefaultTreeModel() {
  294.         DefaultMutableTreeNode      root = new DefaultMutableTreeNode("JTree");
  295.     DefaultMutableTreeNode      parent;
  296.  
  297.     parent = new DefaultMutableTreeNode("colors");
  298.     root.add(parent);
  299.     parent.add(new DefaultMutableTreeNode("blue"));
  300.     parent.add(new DefaultMutableTreeNode("violet"));
  301.     parent.add(new DefaultMutableTreeNode("red"));
  302.     parent.add(new DefaultMutableTreeNode("yellow"));
  303.  
  304.     parent = new DefaultMutableTreeNode("sports");
  305.     root.add(parent);
  306.     parent.add(new DefaultMutableTreeNode("basketball"));
  307.     parent.add(new DefaultMutableTreeNode("soccer"));
  308.     parent.add(new DefaultMutableTreeNode("football"));
  309.     parent.add(new DefaultMutableTreeNode("hockey"));
  310.  
  311.     parent = new DefaultMutableTreeNode("food");
  312.     root.add(parent);
  313.     parent.add(new DefaultMutableTreeNode("hot dogs"));
  314.     parent.add(new DefaultMutableTreeNode("pizza"));
  315.     parent.add(new DefaultMutableTreeNode("ravioli"));
  316.     parent.add(new DefaultMutableTreeNode("bananas"));
  317.         return new DefaultTreeModel(root);
  318.     }
  319.  
  320.     /**
  321.      * Returns a TreeModel wrapping the specified object. If the object
  322.      * is:<ul>
  323.      * <li>an array of Objects,
  324.      * <li>a Hashtable, or
  325.      * <li>a Vector
  326.      * </ul>then a new root node is created with each of the incoming 
  327.      * objects as children. Otherwise, a new root is created with the 
  328.      * specified object as its value.
  329.      *
  330.      * @param value  the Object used as the foundation for the TreeModel
  331.      * @return a TreeModel wrapping the specified object
  332.      */
  333.     protected static TreeModel createTreeModel(Object value) {
  334.         DefaultMutableTreeNode           root;
  335.  
  336.         if((value instanceof Object[]) || (value instanceof Hashtable) ||
  337.            (value instanceof Vector)) {
  338.             root = new DefaultMutableTreeNode("root");
  339.             DynamicUtilTreeNode.createChildren(root, value);
  340.         }
  341.         else {
  342.             root = new DynamicUtilTreeNode("root", value);
  343.         }
  344.         return new DefaultTreeModel(root, false);
  345.     }
  346.  
  347.     /**
  348.      * Returns a JTree with a sample model.
  349.      * The default model used by the tree defines a leaf node as any node without
  350.      * children.
  351.      *
  352.      * @return a JTree with the default model, which defines a leaf node
  353.      *         as any node without children.
  354.      * @see DefaultTreeModel#asksAllowsChildren
  355.      */
  356.     public JTree() {
  357.         this(getDefaultTreeModel());
  358.     }
  359.  
  360.     /**
  361.      * Returns a JTree with each element of the specified array as the
  362.      * child of a new root node which is not displayed.
  363.      * By default, the tree defines a leaf node as any node without
  364.      * children.
  365.      *
  366.      * @param value  an array of Objects
  367.      * @return a JTree with the contents of the array as children of
  368.      *         the root node
  369.      * @see DefaultTreeModel#asksAllowsChildren
  370.      */
  371.     public JTree(Object[] value) {
  372.         this(createTreeModel(value));
  373.         this.setRootVisible(false);
  374.         this.setShowsRootHandles(true);
  375.     }
  376.  
  377.     /**
  378.      * Returns a JTree with each element of the specified Vector as the
  379.      * child of a new root node which is not displayed. By default, the
  380.      * tree defines a leaf node as any node without children.
  381.      *
  382.      * @param value  a Vector
  383.      * @return a JTree with the contents of the Vector as children of
  384.      *         the root node
  385.      * @see DefaultTreeModel#asksAllowsChildren
  386.      */
  387.     public JTree(Vector value) {
  388.         this(createTreeModel(value));
  389.         this.setRootVisible(false);
  390.         this.setShowsRootHandles(true);
  391.     }
  392.  
  393.     /**
  394.      * Returns a JTree created from a Hashtable which does not display
  395.      * the root. Each value-half of the key/value pairs in the HashTable
  396.      * becomes a child of the new root node. By default, the tree defines
  397.      * a leaf node as any node without children.
  398.      *
  399.      * @param value  a Hashtable
  400.      * @return a JTree with the contents of the Hashtable as children of
  401.      *         the root node
  402.      * @see DefaultTreeModel#asksAllowsChildren
  403.      */
  404.     public JTree(Hashtable value) {
  405.         this(createTreeModel(value));
  406.         this.setRootVisible(false);
  407.         this.setShowsRootHandles(true);
  408.     }
  409.  
  410.     /**
  411.      * Returns a JTree with the specified TreeNode as its root, which  
  412.      * displays the root node. By default, the tree defines a leaf node as any node
  413.      * without children.
  414.      *
  415.      * @param root  a TreeNode object
  416.      * @return a JTree with the specified root node
  417.      * @see DefaultTreeModel#asksAllowsChildren
  418.      */
  419.     public JTree(TreeNode root) {
  420.         this(root, false);
  421.     }
  422.  
  423.     /**
  424.      * Returns a JTree with the specified TreeNode as its root, which 
  425.      * displays the root node and which decides whether a node is a 
  426.      * leaf node in the specified manner.
  427.      *
  428.      * @param root  a TreeNode object
  429.      * @param asksAllowsChildren  if false, any node without children is a 
  430.      *              leaf node. If true, only nodes that do not allow 
  431.      *              children are leaf nodes.
  432.      * @return a JTree with the specified root node
  433.      * @see DefaultTreeModel#asksAllowsChildren
  434.      */
  435.     public JTree(TreeNode root, boolean asksAllowsChildren) {
  436.         this(new DefaultTreeModel(root, asksAllowsChildren));
  437.     }
  438.  
  439.     /**
  440.      * Returns an instance of JTree which displays the root node 
  441.      * -- the tree is created using the specified data model.
  442.      *
  443.      * @param newModel  the TreeModel to use as the data model
  444.      * @return a JTree based on the TreeModel
  445.      */
  446.     public JTree(TreeModel newModel) {
  447.         super();
  448.     expandedStack = new Stack();
  449.     toggleClickCount = 2;
  450.     expandedState = new Hashtable();
  451.         setLayout(null);
  452.         rowHeight = 16;
  453.         visibleRowCount = 20;
  454.         rootVisible = true;
  455.         selectionModel = new DefaultTreeSelectionModel();
  456.         cellRenderer = null;
  457.     scrollsOnExpand = true;
  458.         setOpaque(true);
  459.         updateUI();
  460.         setModel(newModel);
  461.     }
  462.  
  463.     /**
  464.      * Returns the L&F object that renders this component.
  465.      *
  466.      * @return the TreeUI object that renders this component
  467.      */
  468.     public TreeUI getUI() {
  469.         return (TreeUI)ui;
  470.     }
  471.  
  472.     /**
  473.      * Sets the L&F object that renders this component.
  474.      *
  475.      * @param ui  the TreeUI L&F object
  476.      * @see UIDefaults#getUI
  477.      */
  478.     public void setUI(TreeUI ui) {
  479.         if ((TreeUI)this.ui != ui) {
  480.             super.setUI(ui);
  481.             repaint();
  482.         }
  483.     }
  484.  
  485.     /**
  486.      * Notification from the UIManager that the L&F has changed. 
  487.      * Replaces the current UI object with the latest version from the 
  488.      * UIManager.
  489.      *
  490.      * @see JComponent#updateUI
  491.      */
  492.     public void updateUI() {
  493.         setUI((TreeUI)UIManager.getUI(this));
  494.         invalidate();
  495.     }
  496.  
  497.  
  498.     /**
  499.      * Returns the name of the L&F class that renders this component.
  500.      *
  501.      * @return "TreeUI"
  502.      * @see JComponent#getUIClassID
  503.      * @see UIDefaults#getUI
  504.      */
  505.     public String getUIClassID() {
  506.         return uiClassID;
  507.     }
  508.  
  509.  
  510.     /**
  511.      * Returns the current TreeCellRenderer that is rendering each cell.
  512.      *
  513.      * @return the TreeCellRenderer that is rendering each cell
  514.      */
  515.     public TreeCellRenderer getCellRenderer() {
  516.         return cellRenderer;
  517.     }
  518.  
  519.     /**
  520.      * Sets the TreeCellRenderer that will be used to draw each cell.
  521.      *
  522.      * @param x  the TreeCellRenderer that is to render each cell
  523.      * @beaninfo
  524.      *        bound: true
  525.      *  description: The TreeCellRenderer that will be used to draw
  526.      *               each cell.
  527.      */
  528.     public void setCellRenderer(TreeCellRenderer x) {
  529.         TreeCellRenderer oldValue = cellRenderer;
  530.  
  531.         cellRenderer = x;
  532.         firePropertyChange(CELL_RENDERER_PROPERTY, oldValue, cellRenderer);
  533.         invalidate();
  534.     }
  535.  
  536.     /**
  537.       * Determines whether the tree is editable. Fires a property
  538.       * change event if the new setting is different from the existing
  539.       * setting.
  540.       *
  541.       * @param flag  a boolean value, true if the tree is editable
  542.       * @beaninfo
  543.       *        bound: true
  544.       *  description: Whether the tree is editable.
  545.       */
  546.     public void setEditable(boolean flag) {
  547.         boolean                 oldValue = this.editable;
  548.  
  549.         this.editable = flag;
  550.         firePropertyChange(EDITABLE_PROPERTY, oldValue, flag);
  551.         if (accessibleContext != null) {
  552.             accessibleContext.firePropertyChange(
  553.                 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 
  554.                 (oldValue ? AccessibleState.EDITABLE : null),
  555.                 (flag ? AccessibleState.EDITABLE : null));
  556.         }
  557.     }
  558.  
  559.     /**
  560.      * Returns true if the tree is editable.
  561.      *
  562.      * @return true if the tree is editable.
  563.      */
  564.     public boolean isEditable() {
  565.         return editable;
  566.     }
  567.  
  568.     /**
  569.      * Sets the cell editor.  A null value implies that the
  570.      * tree cannot be edited.  If this represents a change in the
  571.      * cellEditor, the propertyChange method is invoked on all
  572.      * listeners.
  573.      *
  574.      * @param cellEditor the TreeCellEditor to use
  575.      * @beaninfo
  576.      *        bound: true
  577.      *  description: The cell editor. A null value implies the tree
  578.      *               cannot be edited.
  579.      */
  580.     public void setCellEditor(TreeCellEditor cellEditor) {
  581.         TreeCellEditor        oldEditor = this.cellEditor;
  582.  
  583.         this.cellEditor = cellEditor;
  584.         firePropertyChange(CELL_EDITOR_PROPERTY, oldEditor, cellEditor);
  585.         invalidate();
  586.     }
  587.  
  588.     /**
  589.      * Returns the editor used to edit entries in the tree.
  590.      *
  591.      * @return the TreeCellEditor in use, or null if the tree cannot
  592.      *         be edited
  593.      */
  594.     public TreeCellEditor getCellEditor() {
  595.         return cellEditor;
  596.     }
  597.  
  598.     /**
  599.      * Returns the TreeModel that is providing the data.
  600.      *
  601.      * @return the TreeModel that is providing the data
  602.      */
  603.     public TreeModel getModel() {
  604.         return treeModel;
  605.     }
  606.  
  607.     /**
  608.      * Sets the TreeModel that will provide the data.
  609.      *
  610.      * @param newModel the TreeModel that is to provide the data
  611.      * @beaninfo
  612.      *        bound: true
  613.      *  description: The TreeModel that will provide the data.
  614.      */
  615.     public void setModel(TreeModel newModel) {
  616.         TreeModel oldModel = treeModel;
  617.  
  618.     if(treeModel != null && treeModelListener != null)
  619.         treeModel.removeTreeModelListener(treeModelListener);
  620.  
  621.         if (accessibleContext != null) {
  622.         if (treeModel != null) {
  623.                 treeModel.removeTreeModelListener((TreeModelListener)accessibleContext);
  624.         }
  625.             if (newModel != null) {
  626.             newModel.addTreeModelListener((TreeModelListener)accessibleContext);
  627.         }
  628.         }
  629.  
  630.         treeModel = newModel;
  631.     clearToggledPaths();
  632.     if(treeModel != null) {
  633.         if(treeModelListener == null)
  634.         treeModelListener = createTreeModelListener();
  635.         if(treeModelListener != null)
  636.         treeModel.addTreeModelListener(treeModelListener);
  637.         // Mark the root as expanded, if it isn't a leaf.
  638.         if(!treeModel.isLeaf(treeModel.getRoot()))
  639.         expandedState.put(new TreePath(treeModel.getRoot()),
  640.                   Boolean.TRUE);
  641.     }
  642.         firePropertyChange(TREE_MODEL_PROPERTY, oldModel, treeModel);
  643.         invalidate();
  644.     }
  645.  
  646.     /**
  647.      * Returns true if the root node of the tree is displayed.
  648.      *
  649.      * @return true if the root node of the tree is displayed
  650.      * @see #rootVisible
  651.      */
  652.     public boolean isRootVisible() {
  653.         return rootVisible;
  654.     }
  655.  
  656.     /**
  657.      * Determines whether or not the root node from
  658.      * the TreeModel is visible.
  659.      *
  660.      * @param rootVisible true if the root node of the tree is to be displayed
  661.      * @see #rootVisible
  662.      * @beaninfo
  663.      *        bound: true
  664.      *  description: Whether or not the root node 
  665.      *               from the TreeModel is visible.
  666.      */
  667.     public void setRootVisible(boolean rootVisible) {
  668.         boolean                oldValue = this.rootVisible;
  669.  
  670.         this.rootVisible = rootVisible;
  671.         firePropertyChange(ROOT_VISIBLE_PROPERTY, oldValue, this.rootVisible);
  672.         if (accessibleContext != null) {
  673.             ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  674.         }
  675.     }
  676.  
  677.     /**
  678.      * Determines whether the node handles are to be displayed.
  679.      * 
  680.      * @param newValue true if root handles are to be displayed
  681.      * @see #showsRootHandles
  682.      * @beaninfo
  683.      *        bound: true
  684.      *  description: Whether the node handles are to be
  685.      *               displayed.
  686.      */
  687.     public void setShowsRootHandles(boolean newValue) {
  688.         boolean                oldValue = showsRootHandles;
  689.     TreeModel              model = getModel();
  690.  
  691.         showsRootHandles = newValue;
  692.         firePropertyChange(SHOWS_ROOT_HANDLES_PROPERTY, oldValue,
  693.                            showsRootHandles);
  694.         if (accessibleContext != null) {
  695.             ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  696.         }
  697.     // Make SURE the root is expanded
  698.     if(model != null) {
  699.         expandPath(new TreePath(model.getRoot()));
  700.     }
  701.         invalidate();
  702.     }
  703.  
  704.     /**
  705.      * Returns true if handles for the root nodes are displayed.
  706.      * 
  707.      * @return true if root handles are displayed
  708.      * @see #showsRootHandles
  709.      */
  710.     public boolean getShowsRootHandles()
  711.     {
  712.         return showsRootHandles;
  713.     }
  714.  
  715.     /**
  716.      * Sets the height of each cell.  If the specified value
  717.      * is less than or equal to zero the current cell renderer is
  718.      * queried for each row's height.
  719.      *
  720.      * @param rowHeight the height of each cell, in pixels
  721.      * @beaninfo
  722.      *        bound: true
  723.      *  description: The height of each cell.
  724.      */
  725.     public void setRowHeight(int rowHeight)
  726.     {
  727.         int                oldValue = this.rowHeight;
  728.  
  729.         this.rowHeight = rowHeight;
  730.         firePropertyChange(ROW_HEIGHT_PROPERTY, oldValue, this.rowHeight);
  731.         invalidate();
  732.     }
  733.  
  734.     /**
  735.      * Returns the height of each row.  If the returned value is less than
  736.      * or equal to 0 the height for each row is determined by the
  737.      * renderer.
  738.      *
  739.      * @param the height of each cell, in pixels. Zero or negative if the
  740.      *        height of each row is determined by the tree cell renderer
  741.      */
  742.     public int getRowHeight()
  743.     {
  744.         return rowHeight;
  745.     }
  746.  
  747.     /**
  748.      * Returns true if the height of each display row is a fixed size.
  749.      *
  750.      * @return true if the height of each row is a fixed size
  751.      */
  752.     public boolean isFixedRowHeight()
  753.     {
  754.         return (rowHeight > 0);
  755.     }
  756.  
  757.     /**
  758.      * Specifies whether the UI should use a large model.
  759.      * (Not all UIs will implement this.) Fires a property change
  760.      * for the LARGE_MODEL_PROPERTY.
  761.      * 
  762.      * @param newValue true to suggest a large model to the UI
  763.      * @see #largeModel
  764.      * @beaninfo
  765.      *        bound: true
  766.      *  description: Whether the UI should use a 
  767.      *               large model.
  768.      */
  769.     public void setLargeModel(boolean newValue) {
  770.         boolean                oldValue = largeModel;
  771.  
  772.         largeModel = newValue;
  773.         firePropertyChange(LARGE_MODEL_PROPERTY, oldValue, newValue);
  774.     }
  775.  
  776.     /**
  777.      * Returns true if the tree is configured for a large model.
  778.      * 
  779.      * @return true if a large model is suggested
  780.      * @see #largeModel
  781.      */
  782.     public boolean isLargeModel() {
  783.         return largeModel;
  784.     }
  785.  
  786.     /**
  787.      * Determines what happens when editing is interrupted by selecting
  788.      * another node in the tree, a change in the tree's data, or by some
  789.      * other means. Setting this property to <code>true</code> causes the
  790.      * changes to be automatically saved when editing is interrupted.
  791.      * <p>
  792.      * Fires a property change for the INVOKES_STOP_CELL_EDITING_PROPERTY.
  793.      *
  794.      * @param newValue true means that stopCellEditing is invoked when
  795.      *        editing is interruped, and data is saved. False means that
  796.      *        cancelCellEditing is invoked, and changes are lost.
  797.      * @beaninfo
  798.      *        bound: true
  799.      *  description: Determines what happens when editing is interrupted,
  800.      *               selecting another node in the tree, a change in the
  801.      *               tree's data, or some other means.
  802.      */
  803.     public void setInvokesStopCellEditing(boolean newValue) {
  804.         boolean                  oldValue = invokesStopCellEditing;
  805.  
  806.         invokesStopCellEditing = newValue;
  807.         firePropertyChange(INVOKES_STOP_CELL_EDITING_PROPERTY, oldValue,
  808.                            newValue);
  809.     }
  810.  
  811.     /**
  812.      * Returns the indicator that tells what happens when editing is 
  813.      * interrupted.
  814.      *
  815.      * @return the indicator that tells what happens when editing is 
  816.      *         interrupted
  817.      * @see #setInvokesStopCellEditing
  818.      */
  819.     public boolean getInvokesStopCellEditing() {
  820.         return invokesStopCellEditing;
  821.     }
  822.  
  823.     /**
  824.      * Determines whether or not when a node is expanded, as many of
  825.      * the descendants are scrolled to be inside the viewport as
  826.      * possible. The default is true.
  827.      */
  828.     public void setScrollsOnExpand(boolean newValue) {
  829.     boolean           oldValue = scrollsOnExpand;
  830.  
  831.     scrollsOnExpand = newValue;
  832.         firePropertyChange(SCROLLS_ON_EXPAND_PROPERTY, oldValue,
  833.                            newValue);
  834.     }
  835.  
  836.     /**
  837.      * Returns true if the tree scrolls to show previously hidden children.
  838.      * @return true if when a node is expanded as many of the descendants
  839.      * as possible are scrolled to be visible.
  840.      */
  841.     public boolean getScrollsOnExpand() {
  842.     return scrollsOnExpand;
  843.     }
  844.  
  845.     // NOTE: This property will be enabled in a future release.
  846.     /**
  847.      * Sets the number of mouse clicks before a node will expand or close.
  848.      * The default is two. 
  849.      */
  850. /*
  851.     public void setToggleClickCount(int clickCount) {
  852.     int         oldCount = toggleClickCount;
  853.  
  854.     toggleClickCount = clickCount;
  855.     firePropertyChange(TOGGLE_CLICK_COUNT_PROPERTY, oldCount,
  856.                clickCount);
  857.     }
  858. */
  859.  
  860.     /**
  861.      * Returns the number of mouse clicks needed to expand or close a node.
  862.      * @return number of mouse clicks before node is expanded.
  863.      */
  864. /*
  865.     public int getToggleClickCount() {
  866.     return toggleClickCount;
  867.     }
  868. */
  869.  
  870.     /**
  871.      * Returns <code>isEditable</code>. This is invoked from the UI before
  872.      * editing begins to insure that the given path can be edited. This
  873.      * is provided as an entry point for subclassers to add filtered
  874.      * editing without having to resort to creating a new editor.
  875.      *
  876.      * @return true if every parent node and the node itself is editabled
  877.      * @see #isEditable
  878.      */
  879.     public boolean isPathEditable(TreePath path) {
  880.         return isEditable();
  881.     }
  882.  
  883.     /**
  884.      * Overrides JComponent's getToolTipText method in order to allow 
  885.      * renderer's tips to be used if it has text set.
  886.      * <p>
  887.      * NOTE: For JTree to properly display tooltips of its renderers
  888.      *       JTree must be a registered component with the ToolTipManager.
  889.      *       This can be done by invoking
  890.      *       <code>ToolTipManager.sharedInstance().registerComponent(tree)</code>.
  891.      *       This is not done automaticly!
  892.      *
  893.      * @param event the MouseEvent that initiated the ToolTip display
  894.      */
  895.     public String getToolTipText(MouseEvent event) {
  896.         if(event != null) {
  897.             Point p = event.getPoint();
  898.             int selRow = getRowForLocation(p.x, p.y);
  899.             TreeCellRenderer       r = getCellRenderer();
  900.  
  901.             if(selRow != -1 && r != null) {
  902.                 TreePath     path = getPathForRow(selRow);
  903.                 Object       lastPath = path.getLastPathComponent();
  904.                 Component    rComponent = r.getTreeCellRendererComponent
  905.                     (this, lastPath, isRowSelected(selRow),
  906.                      isExpanded(selRow), getModel().isLeaf(lastPath), selRow,
  907.                      true);
  908.  
  909.                 if(rComponent instanceof JComponent) {
  910.                     MouseEvent      newEvent;
  911.                     Rectangle       pathBounds = getPathBounds(path);
  912.  
  913.                     p.translate(-pathBounds.x, -pathBounds.y);
  914.                     newEvent = new MouseEvent(rComponent, event.getID(),
  915.                                           event.getWhen(),
  916.                                               event.getModifiers(),
  917.                                               p.x, p.y, event.getClickCount(),
  918.                                               event.isPopupTrigger());
  919.                     
  920.                     return ((JComponent)rComponent).getToolTipText(newEvent);
  921.                 }
  922.             }
  923.         }
  924.         return null;
  925.     }
  926.     
  927.     /**
  928.      * Called by the renderers to convert the specified value to
  929.      * text. This implementation returns value.toString(), ignoring
  930.      * all other arguments. To control the conversion, subclass this 
  931.      * method and use any of the arguments you need.
  932.      * 
  933.      * @param value the Object to convert to text
  934.      * @param selected true if the node is selected
  935.      * @param expanded true if the node is expanded
  936.      * @param leaf  true if the node is a leaf node
  937.      * @param row  an int specifying the node's display row, where 0 is 
  938.      *             the first row in the display
  939.      * @param hasFocus true if the node has the focus
  940.      * @return the String representation of the node's value
  941.      */
  942.     public String convertValueToText(Object value, boolean selected,
  943.                                      boolean expanded, boolean leaf, int row,
  944.                                      boolean hasFocus) {
  945.         if(value != null)
  946.             return value.toString();
  947.         return "";
  948.     }
  949.  
  950.     //
  951.     // The following are convenience methods that get forwarded to the
  952.     // current TreeUI.
  953.     //
  954.  
  955.     /**
  956.      * Returns the number of rows that are currently being displayed.
  957.      *
  958.      * @return the number of rows that are being displayed
  959.      */
  960.     public int getRowCount() {
  961.         TreeUI            tree = getUI();
  962.  
  963.         if(tree != null)
  964.             return tree.getRowCount(this);
  965.         return 0;
  966.     }
  967.  
  968.     /** 
  969.      * Selects the node identified by the specified path.  If any
  970.      * component of the path is hidden (under a collapsed node), it is 
  971.      * exposed (made viewable).
  972.      *
  973.      * @param path the TreePath specifying the node to select
  974.      */
  975.     public void setSelectionPath(TreePath path) {
  976.     makeVisible(path);
  977.         getSelectionModel().setSelectionPath(path);
  978.     }
  979.  
  980.     /** 
  981.      * Selects the nodes identified by the specified array of paths.
  982.      * If any component in any of the paths is hidden (under a collapsed
  983.      * node), it is exposed (made viewable).
  984.      *
  985.      * @param paths an array of TreePath objects that specifies the nodes
  986.      *        to select
  987.      */
  988.     public void setSelectionPaths(TreePath[] paths) {
  989.     if(paths != null) {
  990.         for(int counter = paths.length - 1; counter >= 0; counter--)
  991.         makeVisible(paths[counter]);
  992.     }
  993.         getSelectionModel().setSelectionPaths(paths);
  994.     }
  995.  
  996.     /**
  997.      * Selects the node at the specified row in the display.
  998.      *
  999.      * @param row  the row to select, where 0 is the first row in
  1000.      *             the display
  1001.      */
  1002.     public void setSelectionRow(int row) {
  1003.         int[]             rows = { row };
  1004.  
  1005.         setSelectionRows(rows);
  1006.     }
  1007.  
  1008.     /**
  1009.      * Selects the nodes corresponding to each of the specified rows
  1010.      * in the display. If a particular element of <code>rows</code> is
  1011.      * < 0 or >= getRowCount, it will be ignored. If none of the elements
  1012.      * in <code>rows</code> are valid rows, the selection will
  1013.      * be cleared. That is it will be as if <code>clearSelection</code>
  1014.      * was invoked.
  1015.      * 
  1016.      * @param rows  an array of ints specifying the rows to select,
  1017.      *              where 0 indicates the first row in the display
  1018.      */
  1019.     public void setSelectionRows(int[] rows) {
  1020.         TreeUI               ui = getUI();
  1021.  
  1022.         if(ui != null && rows != null) {
  1023.             int                  numRows = rows.length;
  1024.             TreePath[]           paths = new TreePath[numRows];
  1025.  
  1026.             for(int counter = 0; counter < numRows; counter++)
  1027.                 paths[counter] = ui.getPathForRow(this, rows[counter]);
  1028.             setSelectionPaths(paths);
  1029.         }
  1030.     }
  1031.  
  1032.     /**
  1033.      * Adds the node identified by the specified TreePath to the current
  1034.      * selection. If any component of the path isn't viewable, it is 
  1035.      * made viewable.
  1036.      *
  1037.      * @param path the TreePath to add
  1038.      */
  1039.     public void addSelectionPath(TreePath path) {
  1040.     makeVisible(path);
  1041.         getSelectionModel().addSelectionPath(path);
  1042.     }
  1043.  
  1044.     /**
  1045.      * Adds each path in the array of paths to the current selection. If
  1046.      * any component of any of the paths isn't viewable, it is
  1047.      * made viewable.
  1048.      *
  1049.      * @param paths an array of TreePath objects that specifies the nodes
  1050.      *              to add
  1051.      */
  1052.     public void addSelectionPaths(TreePath[] paths) {
  1053.     if(paths != null) {
  1054.         for(int counter = paths.length - 1; counter >= 0; counter--)
  1055.         makeVisible(paths[counter]);
  1056.     }
  1057.     getSelectionModel().addSelectionPaths(paths);
  1058.     }
  1059.  
  1060.     /**
  1061.      * Adds the path at the specified row to the current selection.
  1062.      *
  1063.      * @param row  an int specifying the row of the node to add,
  1064.      *             where 0 is the first row in the display
  1065.      */
  1066.     public void addSelectionRow(int row) {
  1067.         int[]      rows = { row };
  1068.  
  1069.         addSelectionRows(rows);
  1070.     }
  1071.  
  1072.     /**
  1073.      * Adds the paths at each of the specified rows to the current selection.
  1074.      * 
  1075.      * @param rows  an array of ints specifying the rows to add,
  1076.      *              where 0 indicates the first row in the display
  1077.      */
  1078.     public void addSelectionRows(int[] rows) {
  1079.         TreeUI             ui = getUI();
  1080.  
  1081.         if(ui != null && rows != null) {
  1082.             int                  numRows = rows.length;
  1083.             TreePath[]           paths = new TreePath[numRows];
  1084.  
  1085.             for(int counter = 0; counter < numRows; counter++)
  1086.                 paths[counter] = ui.getPathForRow(this, rows[counter]);
  1087.             addSelectionPaths(paths);
  1088.         }
  1089.     }
  1090.  
  1091.     /**
  1092.      * Returns the last path component in the first node of the current 
  1093.      * selection.
  1094.      *
  1095.      * @return the last Object in the first selected node's TreePath,
  1096.      *         or null if nothing is selected
  1097.      * @see TreePath#getLastPathComponent
  1098.      */
  1099.     public Object getLastSelectedPathComponent() {
  1100.         TreePath     selPath = getSelectionModel().getSelectionPath();
  1101.  
  1102.         if(selPath != null)
  1103.             return selPath.getLastPathComponent();
  1104.         return null;
  1105.     }
  1106.  
  1107.     /**
  1108.      * Returns the path to the first selected node.
  1109.      *
  1110.      * @return the TreePath for the first selected node, or null if
  1111.      *         nothing is currently selected
  1112.      */
  1113.     public TreePath getSelectionPath() {
  1114.         return getSelectionModel().getSelectionPath();
  1115.     }
  1116.  
  1117.     /**
  1118.      * Returns the paths of all selected values.
  1119.      *
  1120.      * @return an array of TreePath objects indicating the selected
  1121.      *         nodes, or null if nothing is currently selected.
  1122.      */
  1123.     public TreePath[] getSelectionPaths() {
  1124.         return getSelectionModel().getSelectionPaths();
  1125.     }
  1126.  
  1127.     /**
  1128.      * Returns all of the currently selected rows. This method is simply
  1129.      * forwarded to the TreeSelectionModel. If nothing is selected null
  1130.      * or an empty array with be returned, based on the TreeSelectionModel
  1131.      * implementation.
  1132.      *
  1133.      * @return an array of ints that identifies all currently selected rows
  1134.      *         where 0 is the first row in the display
  1135.      */
  1136.     public int[] getSelectionRows() {
  1137.         return getSelectionModel().getSelectionRows();
  1138.     }
  1139.  
  1140.     /**
  1141.      * Returns the number of nodes selected.
  1142.      *
  1143.      * @return the number of nodes selected
  1144.      */
  1145.     public int getSelectionCount() {
  1146.         return selectionModel.getSelectionCount();
  1147.     }
  1148.  
  1149.     /**
  1150.      * Gets the first selected row.
  1151.      *
  1152.      * @return an int designating the first selected row, where 0 is the 
  1153.      *         first row in the display
  1154.      */
  1155.     public int getMinSelectionRow() {
  1156.         return getSelectionModel().getMinSelectionRow();
  1157.     }
  1158.  
  1159.     /**
  1160.      * Gets the last selected row.
  1161.      *
  1162.      * @return an int designating the last selected row, where 0 is the 
  1163.      *         first row in the display
  1164.      */
  1165.     public int getMaxSelectionRow() {
  1166.         return getSelectionModel().getMaxSelectionRow();
  1167.     }
  1168.  
  1169.     /**
  1170.      * Returns the row index of the last node added to the selection.
  1171.      *
  1172.      * @return an int giving the row index of the last node added to the
  1173.      *         selection, where 0 is the first row in the display
  1174.      */
  1175.     public int getLeadSelectionRow() {
  1176.         return getSelectionModel().getLeadSelectionRow();
  1177.     }
  1178.  
  1179.     /**
  1180.      * Returns the path of the last node added to the selection.
  1181.      *
  1182.      * @return the TreePath of the last node added to the selection.
  1183.      */
  1184.     public TreePath getLeadSelectionPath() {
  1185.         return getSelectionModel().getLeadSelectionPath();
  1186.     }
  1187.  
  1188.     /**
  1189.      * Returns true if the item identified by the path is currently selected.
  1190.      *
  1191.      * @param path a TreePath identifying a node
  1192.      * @return true if the node is selected
  1193.      */
  1194.     public boolean isPathSelected(TreePath path) {
  1195.         return getSelectionModel().isPathSelected(path);
  1196.     }
  1197.  
  1198.     /**
  1199.      * Returns true if the node identitifed by row is selected.
  1200.      *
  1201.      * @param row  an int specifying a display row, where 0 is the first
  1202.      *             row in the display
  1203.      * @return true if the node is selected
  1204.      */
  1205.     public boolean isRowSelected(int row) {
  1206.         return getSelectionModel().isRowSelected(row);
  1207.     }
  1208.  
  1209.     /**
  1210.      * Returns an Enumeration of the descendants of <code>path</code> that
  1211.      * are currently expanded. If <code>path</code> is not currently
  1212.      * expanded, this will return null. If you expand/collapse nodes while
  1213.      * iterating over the returned Enumeration this may not return all
  1214.      * the expanded paths, or may return paths that are no longer expanded.
  1215.      */
  1216.     public Enumeration getExpandedDescendants(TreePath parent) {
  1217.     if(!isExpanded(parent))
  1218.         return null;
  1219.  
  1220.     Enumeration       toggledPaths = expandedState.keys();
  1221.     Vector            elements = new Vector();
  1222.     TreePath          path;
  1223.     Object            value;
  1224.  
  1225.     if(toggledPaths != null) {
  1226.         while(toggledPaths.hasMoreElements()) {
  1227.         path = (TreePath)toggledPaths.nextElement();
  1228.         value = expandedState.get(path);
  1229.         // Add the path if it is expanded, a descendant of parent,
  1230.         // and it is visible (all parents expanded). This is rather
  1231.         // expensive!
  1232.         if(value != null && ((Boolean)value).booleanValue() &&
  1233.            parent.isDescendant(path) && isVisible(path)) {
  1234.             elements.addElement(path);
  1235.         }
  1236.         }
  1237.     }
  1238.     return elements.elements();
  1239.     }
  1240.  
  1241.     /**
  1242.      * Returns true if the node identified by the path has ever been
  1243.      * expanded.
  1244.      */
  1245.     public boolean hasBeenExpanded(TreePath path) {
  1246.     return (path != null && expandedState.get(path) != null);
  1247.     }
  1248.  
  1249.     /**
  1250.      * Returns true if the node identified by the path is currently expanded,
  1251.      * 
  1252.      * @param path  the TreePath specifying the node to check
  1253.      * @return false if any of the nodes in the node's path are collapsed, 
  1254.      *               true if all nodes in the path are expanded
  1255.      */
  1256.     public boolean isExpanded(TreePath path) {
  1257.     if(path == null)
  1258.         return false;
  1259.  
  1260.     // Is this node expanded?
  1261.     Object          value = expandedState.get(path);
  1262.  
  1263.     if(value == null || !((Boolean)value).booleanValue())
  1264.         return false;
  1265.  
  1266.     // It is, make sure its parent is also expanded.
  1267.     TreePath        parentPath = path.getParentPath();
  1268.  
  1269.     if(parentPath != null)
  1270.         return isExpanded(parentPath);
  1271.         return true;
  1272.     }
  1273.  
  1274.     /**
  1275.      * Returns true if the node at the specified display row is currently
  1276.      * expanded.
  1277.      * 
  1278.      * @param row  the row to check, where 0 is the first row in the 
  1279.      *             display
  1280.      * @return true if the node is currently expanded, otherwise false
  1281.      */
  1282.     public boolean isExpanded(int row) {
  1283.         TreeUI                  tree = getUI();
  1284.  
  1285.         if(tree != null) {
  1286.         TreePath         path = tree.getPathForRow(this, row);
  1287.  
  1288.         if(path != null)
  1289.         return isExpanded(path);
  1290.     }
  1291.         return false;
  1292.     }
  1293.  
  1294.     /**
  1295.      * Returns true if the value identified by path is currently collapsed,
  1296.      * this will return false if any of the values in path are currently
  1297.      * not being displayed.
  1298.      * 
  1299.      * @param path  the TreePath to check
  1300.      * @return true if any of the nodes in the node's path are collapsed, 
  1301.      *               false if all nodes in the path are expanded
  1302.      */
  1303.     public boolean isCollapsed(TreePath path) {
  1304.     return !isExpanded(path);
  1305.     }
  1306.  
  1307.     /**
  1308.      * Returns true if the node at the specified display row is collapsed.
  1309.      * 
  1310.      * @param row  the row to check, where 0 is the first row in the 
  1311.      *             display
  1312.      * @return true if the node is currently collapsed, otherwise false
  1313.      */
  1314.     public boolean isCollapsed(int row) {
  1315.     return !isExpanded(row);
  1316.     }
  1317.  
  1318.     /**
  1319.      * Ensures that the node identified by path is currently viewable.
  1320.      *
  1321.      * @param path  the TreePath to make visible
  1322.      */
  1323.     public void makeVisible(TreePath path) {
  1324.         if(path != null) {
  1325.         TreePath        parentPath = path.getParentPath();
  1326.  
  1327.         if(parentPath != null) {
  1328.         expandPath(parentPath);
  1329.         }
  1330.         }
  1331.     }
  1332.  
  1333.     /**
  1334.      * Returns true if the value identified by path is currently viewable,
  1335.      * which means it is either the root or all of its parents are exapnded  ,
  1336.      * Otherwise, this method returns false. 
  1337.      *
  1338.      * @return true if the node is viewable, otherwise false
  1339.      */
  1340.     public boolean isVisible(TreePath path) {
  1341.         if(path != null) {
  1342.         TreePath        parentPath = path.getParentPath();
  1343.  
  1344.         if(parentPath != null)
  1345.         return isExpanded(parentPath);
  1346.         // Root.
  1347.         return true;
  1348.     }
  1349.         return false;
  1350.     }
  1351.  
  1352.     /**
  1353.      * Returns the Rectangle that the specified node will be drawn
  1354.      * into. Returns null if any component in the path is hidden
  1355.      * (under a collapsed parent).
  1356.      * <p>
  1357.      * Note:<br>
  1358.      * This method returns a valid rectangle, even if the specified
  1359.      * node is not currently displayed.
  1360.      *
  1361.      * @param path the TreePath identifying the node
  1362.      * @return the Rectangle the node is drawn in, or null 
  1363.      */
  1364.     public Rectangle getPathBounds(TreePath path) {
  1365.         TreeUI                   tree = getUI();
  1366.  
  1367.         if(tree != null)
  1368.             return tree.getPathBounds(this, path);
  1369.         return null;
  1370.     }
  1371.  
  1372.     /**
  1373.      * Returns the Rectangle that the node at the specified row is
  1374.      * drawn in.
  1375.      *
  1376.      * @param row  the row to be drawn, where 0 is the first row in the 
  1377.      *             display
  1378.      * @return the Rectangle the node is drawn in 
  1379.      */
  1380.     public Rectangle getRowBounds(int row) {
  1381.     TreePath          path = getPathForRow(row);
  1382.  
  1383.     return getPathBounds(getPathForRow(row));
  1384.     }
  1385.  
  1386.     /**
  1387.      * Makes sure all the path components in path are expanded (except
  1388.      * for the last path component) and scrolls so that the 
  1389.      * node identified by the path is displayed. Only works when this
  1390.      * JTree is contained in a JSrollPane.
  1391.      * 
  1392.      * @param path  the TreePath identifying the node to bring into view
  1393.      */
  1394.     public void scrollPathToVisible(TreePath path) {
  1395.     if(path != null) {
  1396.         makeVisible(path);
  1397.  
  1398.         Rectangle          bounds = getPathBounds(path);
  1399.  
  1400.         if(bounds != null) {
  1401.         scrollRectToVisible(bounds);
  1402.         if (accessibleContext != null) {
  1403.             ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1404.         }
  1405.         }
  1406.     }
  1407.     }
  1408.  
  1409.     /**
  1410.      * Scrolls the item identified by row until it is displayed. The minimum
  1411.      * of amount of scrolling necessary to bring the row into view
  1412.      * is performed. Only works when this JTree is contained in a
  1413.      * JSrollPane.
  1414.      *
  1415.      * @param row  an int specifying the row to scroll, where 0 is the
  1416.      *             first row in the display
  1417.      */
  1418.     public void scrollRowToVisible(int row) {
  1419.     scrollPathToVisible(getPathForRow(row));
  1420.     }
  1421.  
  1422.     /**
  1423.      * Returns the path for the specified row.
  1424.      * <!-->If row is not visible null is returned.<-->
  1425.      *
  1426.      * @param row  an int specifying a row
  1427.      * @return the TreePath to the specified node, null if
  1428.      *         row < 0 or row > getRowCount()
  1429.      */
  1430.     public TreePath getPathForRow(int row) {
  1431.         TreeUI                  tree = getUI();
  1432.  
  1433.         if(tree != null)
  1434.             return tree.getPathForRow(this, row);
  1435.         return null;
  1436.     }
  1437.  
  1438.     /**
  1439.      * Returns the row that displays the node identified by the specified
  1440.      * path. 
  1441.      * 
  1442.      * @param path  the TreePath identifying a node
  1443.      * @return an int specifying the display row, where 0 is the first
  1444.      *         row in the display, or -1 if any of the elements in path
  1445.      *         are hidden under a collapsed parent.
  1446.      */
  1447.     public int getRowForPath(TreePath path) {
  1448.         TreeUI                  tree = getUI();
  1449.  
  1450.         if(tree != null)
  1451.             return tree.getRowForPath(this, path);
  1452.         return -1;
  1453.     }
  1454.  
  1455.     /**
  1456.      * Ensures that the node identified by the specified path is 
  1457.      * expanded and viewable.
  1458.      * 
  1459.      * @param path  the TreePath identifying a node
  1460.      */
  1461.     public void expandPath(TreePath path) {
  1462.     // Only expand if not leaf!
  1463.     TreeModel          model = getModel();
  1464.  
  1465.     if(path != null && model != null && 
  1466.        !model.isLeaf(path.getLastPathComponent())) {
  1467.         setExpandedState(path, true);
  1468.     }
  1469.     }
  1470.  
  1471.     /**
  1472.      * Ensures that the node in the specified row is expanded and
  1473.      * viewable. <p> If <code>row</code> is < 0 or >= getRowCount this
  1474.      * will have no effect.
  1475.      *
  1476.      * @param row  an int specifying a display row, where 0 is the
  1477.      *             first row in the display
  1478.      */
  1479.     public void expandRow(int row) {
  1480.     expandPath(getPathForRow(row));
  1481.     }
  1482.  
  1483.     /**
  1484.      * Ensures that the node identified by the specified path is 
  1485.      * collapsed and viewable.
  1486.      * 
  1487.      * @param path  the TreePath identifying a node
  1488.       */
  1489.     public void collapsePath(TreePath path) {
  1490.     setExpandedState(path, false);
  1491.     }
  1492.  
  1493.     /**
  1494.      * Ensures that the node in the specified row is collapsed.
  1495.      * <p> If <code>row</code> is < 0 or >= getRowCount this
  1496.      * will have no effect.
  1497.      *
  1498.      * @param row  an int specifying a display row, where 0 is the
  1499.      *             first row in the display
  1500.       */
  1501.     public void collapseRow(int row) {
  1502.     collapsePath(getPathForRow(row));
  1503.     }
  1504.  
  1505.     /**
  1506.      * Returns the path for the node at the specified location.
  1507.      *
  1508.      * @param x an int giving the number of pixels horizontally from
  1509.      *          the left edge of the display area, minus any left margin
  1510.      * @param y an int giving the number of pixels vertically from
  1511.      *          the top of the display area, minus any top margin
  1512.      * @return  the TreePath for the node at that location
  1513.      */
  1514.     public TreePath getPathForLocation(int x, int y) {
  1515.         TreePath          closestPath = getClosestPathForLocation(x, y);
  1516.  
  1517.         if(closestPath != null) {
  1518.             Rectangle       pathBounds = getPathBounds(closestPath);
  1519.  
  1520.             if(x >= pathBounds.x && x < (pathBounds.x + pathBounds.width) &&
  1521.                y >= pathBounds.y && y < (pathBounds.y + pathBounds.height))
  1522.                 return closestPath;
  1523.         }
  1524.         return null;
  1525.     }
  1526.  
  1527.     /**
  1528.      * Returns the row for the specified location. 
  1529.      *
  1530.      * @param x an int giving the number of pixels horizontally from
  1531.      *          the left edge of the display area, minus any left margin
  1532.      * @param y an int giving the number of pixels vertically from
  1533.      *          the top of the display area, minus any top margin
  1534.      * @return the row corresponding to the location, or -1 if the
  1535.      *         location is not within the bounds of a displayed cell
  1536.      * @see #getClosestRowForLocation
  1537.      */
  1538.     public int getRowForLocation(int x, int y) {
  1539.     return getRowForPath(getPathForLocation(x, y));
  1540.     }
  1541.  
  1542.     /**
  1543.      * Returns the path to the node that is closest to x,y.  If
  1544.      * no nodes are currently viewable, or there is no model, returns
  1545.      * null, otherwise it always returns a valid path.  To test if
  1546.      * the node is exactly at x, y, get the node's bounds and
  1547.      * test x, y against that.
  1548.      *
  1549.      * @param x an int giving the number of pixels horizontally from
  1550.      *          the left edge of the display area, minus any left margin
  1551.      * @param y an int giving the number of pixels vertically from
  1552.      *          the top of the display area, minus any top margin
  1553.      * @return  the TreePath for the node closest to that location,
  1554.      *          null if nothing is viewable or there is no model
  1555.      *
  1556.      * @see #getPathForLocation
  1557.      * @see #getPathBounds
  1558.      */
  1559.     public TreePath getClosestPathForLocation(int x, int y) {
  1560.         TreeUI                  tree = getUI();
  1561.  
  1562.         if(tree != null)
  1563.             return tree.getClosestPathForLocation(this, x, y);
  1564.         return null;
  1565.     }
  1566.  
  1567.     /**
  1568.      * Returns the row to the node that is closest to x,y.  If no nodes
  1569.      * are viewable or there is no model, returns -1. Otherwise,
  1570.      * it always returns a valid row.  To test if the returned object is 
  1571.      * exactly at x, y, get the bounds for the node at the returned
  1572.      * row and test x, y against that.
  1573.      *
  1574.      * @param x an int giving the number of pixels horizontally from
  1575.      *          the left edge of the display area, minus any left margin
  1576.      * @param y an int giving the number of pixels vertically from
  1577.      *          the top of the display area, minus any top margin
  1578.      * @return the row closest to the location, -1 if nothing is
  1579.      *         viewable or there is no model
  1580.      *
  1581.      * @see #getRowForLocation
  1582.      * @see #getRowBounds
  1583.      */
  1584.     public int getClosestRowForLocation(int x, int y) {
  1585.     return getRowForPath(getClosestPathForLocation(x, y));
  1586.     }
  1587.  
  1588.     /**
  1589.      * Returns true if the tree is being edited. The item that is being
  1590.      * edited can be obtained using <code>getSelectionPath</code>.
  1591.      *
  1592.      * @return true if the user is currently editing a node
  1593.      * @see #getSelectionPath
  1594.      */
  1595.     public boolean isEditing() {
  1596.         TreeUI                  tree = getUI();
  1597.  
  1598.         if(tree != null)
  1599.             return tree.isEditing(this);
  1600.         return false;
  1601.     }
  1602.  
  1603.     /**
  1604.      * Ends the current editing session. (The DefaultTreeCellEditor 
  1605.      * object saves any edits that are currently in progress on a cell.
  1606.      * Other implementations may operate differently.) 
  1607.      * Has no effect if the tree isn't being edited.
  1608.      * <blockquote>
  1609.      * <b>Note:</b><br>
  1610.      * To make edit-saves automatic whenever the user changes
  1611.      * their position in the tree, use {@link #setInvokesStopCellEditing}.
  1612.      * </blockquote>
  1613.      *
  1614.      * @return true if editing was in progress and is now stopped,
  1615.      *              false if editing was not in progress
  1616.      */
  1617.     public boolean stopEditing() {
  1618.         TreeUI                  tree = getUI();
  1619.  
  1620.         if(tree != null)
  1621.             return tree.stopEditing(this);
  1622.         return false;
  1623.     }
  1624.  
  1625.     /**
  1626.      * Cancels the current editing session. Has no effect if the
  1627.      * tree isn't being edited.
  1628.      */
  1629.     public void  cancelEditing() {
  1630.         TreeUI                  tree = getUI();
  1631.  
  1632.         if(tree != null)
  1633.         tree.cancelEditing(this);
  1634.     }
  1635.  
  1636.     /**
  1637.      * Selects the node identified by the specified path and initiates
  1638.      * editing.  The edit-attempt fails if the CellEditor does not allow
  1639.      * editing for the specified item.
  1640.      * 
  1641.      * @param path  the TreePath identifying a node
  1642.      */
  1643.     public void startEditingAtPath(TreePath path) {
  1644.         TreeUI                  tree = getUI();
  1645.  
  1646.         if(tree != null)
  1647.             tree.startEditingAtPath(this, path);
  1648.     }
  1649.  
  1650.     /**
  1651.      * Returns the path to the element that is currently being edited.
  1652.      *
  1653.      * @return  the TreePath for the node being edited
  1654.      */
  1655.     public TreePath getEditingPath() {
  1656.         TreeUI                  tree = getUI();
  1657.  
  1658.         if(tree != null)
  1659.             return tree.getEditingPath(this);
  1660.         return null;
  1661.     }
  1662.  
  1663.     //
  1664.     // Following are primarily convenience methods for mapping from
  1665.     // row based selections to path selections.  Sometimes it is
  1666.     // easier to deal with these than paths (mouse downs, key downs
  1667.     // usually just deal with index based selections).
  1668.     // Since row based selections require a UI many of these won't work
  1669.     // without one.
  1670.     //
  1671.  
  1672.     /**
  1673.      * Sets the tree's selection model. When a null value is specified
  1674.      * an empty electionModel is used, which does not allow selections.
  1675.      *
  1676.      * @param selectionModel the TreeSelectionModel to use, or null to
  1677.      *        disable selections
  1678.      * @see TreeSelectionModel
  1679.      * @beaninfo
  1680.      *        bound: true
  1681.      *  description: The tree's selection model.
  1682.      */
  1683.     public void setSelectionModel(TreeSelectionModel selectionModel) {
  1684.         if(selectionModel == null)
  1685.             selectionModel = EmptySelectionModel.sharedInstance();
  1686.  
  1687.         TreeSelectionModel         oldValue = this.selectionModel;
  1688.  
  1689.         if (accessibleContext != null) {
  1690.            this.selectionModel.removeTreeSelectionListener((TreeSelectionListener)accessibleContext);
  1691.            selectionModel.addTreeSelectionListener((TreeSelectionListener)accessibleContext);
  1692.         }
  1693.  
  1694.         this.selectionModel = selectionModel;
  1695.         firePropertyChange(SELECTION_MODEL_PROPERTY, oldValue,
  1696.                            this.selectionModel);
  1697.  
  1698.         if (accessibleContext != null) {
  1699.             accessibleContext.firePropertyChange(
  1700.                     AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
  1701.                     new Boolean(false), new Boolean(true));
  1702.         }
  1703.     }
  1704.  
  1705.     /**
  1706.      * Returns the model for selections. This should always return a 
  1707.      * non-null value. If you don't want to allow anything to be selected
  1708.      * set the selection model to null, which forces an empty
  1709.      * selection model to be used.
  1710.      *
  1711.      * @param the TreeSelectionModel in use
  1712.      * @see #setSelectionModel
  1713.      */
  1714.     public TreeSelectionModel getSelectionModel() {
  1715.         return selectionModel;
  1716.     }
  1717.  
  1718.     /**
  1719.      * Returns JTreePath instances representing the path between index0
  1720.      * and index1 (including index1).  Returns null if there is no tree.
  1721.      *
  1722.      * @param index0  an int specifying a display row, where 0 is the
  1723.      *                first row in the display
  1724.      * @param index0  an int specifying a second display row
  1725.      * @return an array of TreePath objects, one for each node between
  1726.      *         index0 and index1, inclusive
  1727.      */
  1728.     protected TreePath[] getPathBetweenRows(int index0, int index1) {
  1729.         int              newMinIndex, newMaxIndex;
  1730.         TreeUI           tree = getUI();
  1731.  
  1732.         newMinIndex = Math.min(index0, index1);
  1733.         newMaxIndex = Math.max(index0, index1);
  1734.  
  1735.         if(tree != null) {
  1736.             TreePath[]            selection = new TreePath[newMaxIndex -
  1737.                                                             newMinIndex + 1];
  1738.  
  1739.             for(int counter = newMinIndex; counter <= newMaxIndex; counter++)
  1740.                 selection[counter - newMinIndex] = tree.getPathForRow(this,
  1741.                                       counter);
  1742.             return selection;
  1743.         }
  1744.         return null;
  1745.     }
  1746.  
  1747.     /**
  1748.      * Selects the nodes between index0 and index1, inclusive.
  1749.      *
  1750.      * @param index0  an int specifying a display row, where 0 is the
  1751.      *                first row in the display
  1752.      * @param index0  an int specifying a second display row
  1753.     */
  1754.     public void setSelectionInterval(int index0, int index1) {
  1755.         TreePath[]         paths = getPathBetweenRows(index0, index1);
  1756.  
  1757.         this.getSelectionModel().setSelectionPaths(paths);
  1758.     }
  1759.  
  1760.     /**
  1761.      * Adds the paths between index0 and index1, inclusive, to the 
  1762.      * selection.
  1763.      *
  1764.      * @param index0  an int specifying a display row, where 0 is the
  1765.      *                first row in the display
  1766.      * @param index0  an int specifying a second display row
  1767.      */
  1768.     public void addSelectionInterval(int index0, int index1) {
  1769.         TreePath[]         paths = getPathBetweenRows(index0, index1);
  1770.  
  1771.         this.getSelectionModel().addSelectionPaths(paths);
  1772.     }
  1773.  
  1774.     /**
  1775.      * Removes the nodes between index0 and index1, inclusive, from the 
  1776.      * selection.
  1777.      *
  1778.      * @param index0  an int specifying a display row, where 0 is the
  1779.      *                first row in the display
  1780.      * @param index0  an int specifying a second display row
  1781.      */
  1782.     public void removeSelectionInterval(int index0, int index1) {
  1783.         TreePath[]         paths = getPathBetweenRows(index0, index1);
  1784.  
  1785.         this.getSelectionModel().removeSelectionPaths(paths);
  1786.     }
  1787.  
  1788.     /**
  1789.      * Removes the node identified by the specified path from the current
  1790.      * selection.
  1791.      * 
  1792.      * @param path  the TreePath identifying a node
  1793.      */
  1794.     public void removeSelectionPath(TreePath path) {
  1795.         this.getSelectionModel().removeSelectionPath(path);
  1796.     }
  1797.  
  1798.     /**
  1799.      * Removes the nodes identified by the specified paths from the 
  1800.      * current selection.
  1801.      *
  1802.      * @param paths an array of TreePath objects that specifies the nodes
  1803.      *              to remove
  1804.      */
  1805.     public void removeSelectionPaths(TreePath[] paths) {
  1806.         this.getSelectionModel().removeSelectionPaths(paths);
  1807.     }
  1808.  
  1809.     /**
  1810.      * Removes the path at the index <code>row</code> from the current
  1811.      * selection.
  1812.      * 
  1813.      * @param path  the TreePath identifying the node to remove
  1814.      */
  1815.     public void removeSelectionRow(int row) {
  1816.         int[]             rows = { row };
  1817.  
  1818.         removeSelectionRows(rows);
  1819.     }
  1820.  
  1821.     /**
  1822.      * Removes the paths that are selected at each of the specified
  1823.      * rows.
  1824.      *
  1825.      * @param row  an array of ints specifying display rows, where 0 is 
  1826.      *             the first row in the display
  1827.      */
  1828.     public void removeSelectionRows(int[] rows) {
  1829.         TreeUI             ui = getUI();
  1830.  
  1831.         if(ui != null && rows != null) {
  1832.             int                  numRows = rows.length;
  1833.             TreePath[]           paths = new TreePath[numRows];
  1834.  
  1835.             for(int counter = 0; counter < numRows; counter++)
  1836.                 paths[counter] = ui.getPathForRow(this, rows[counter]);
  1837.             removeSelectionPaths(paths);
  1838.         }
  1839.     }
  1840.  
  1841.     /**
  1842.      * Clears the selection.
  1843.      */
  1844.     public void clearSelection() {
  1845.         getSelectionModel().clearSelection();
  1846.     }
  1847.  
  1848.     /**
  1849.      * Returns true if the selection is currently empty.
  1850.      *
  1851.      * @return true if the selection is currently empty
  1852.      */
  1853.     public boolean isSelectionEmpty() {
  1854.         return getSelectionModel().isSelectionEmpty();
  1855.     }
  1856.  
  1857.     /**
  1858.      * Adds a listener for TreeExpansion events.
  1859.      *
  1860.      * @param tel a TreeExpansionListener that will be notified when
  1861.      *            a tree node is expanded or collapsed (a "negative
  1862.      *            expansion")
  1863.      */
  1864.     public void addTreeExpansionListener(TreeExpansionListener tel) {
  1865.         listenerList.add(TreeExpansionListener.class, tel);
  1866.     }
  1867.  
  1868.     /**
  1869.      * Removes a listener for TreeExpansion events.
  1870.      *
  1871.      * @param tel the TreeExpansionListener to remove
  1872.      */
  1873.     public void removeTreeExpansionListener(TreeExpansionListener tel) {
  1874.         listenerList.remove(TreeExpansionListener.class, tel);
  1875.     }
  1876.  
  1877.     /**
  1878.      * Adds a listener for TreeWillExpand events.
  1879.      *
  1880.      * @param tel a TreeWillExpandListener that will be notified when
  1881.      *            a tree node will be expanded or collapsed (a "negative
  1882.      *            expansion")
  1883.      */
  1884.     public void addTreeWillExpandListener(TreeWillExpandListener tel) {
  1885.         listenerList.add(TreeWillExpandListener.class, tel);
  1886.     }
  1887.  
  1888.     /**
  1889.      * Removes a listener for TreeWillExpand events.
  1890.      *
  1891.      * @param tel the TreeWillExpandListener to remove
  1892.      */
  1893.     public void removeTreeWillExpandListener(TreeWillExpandListener tel) {
  1894.         listenerList.remove(TreeWillExpandListener.class, tel);
  1895.     }
  1896.  
  1897.     /**
  1898.      * Notify all listeners that have registered interest for
  1899.      * notification on this event type.  The event instance 
  1900.      * is lazily created using the parameters passed into 
  1901.      * the fire method.
  1902.      *
  1903.      * @param path the TreePath indicating the node that was expanded
  1904.      * @see EventListenerList
  1905.      */
  1906.      public void fireTreeExpanded(TreePath path) {
  1907.         // Guaranteed to return a non-null array
  1908.         Object[] listeners = listenerList.getListenerList();
  1909.         TreeExpansionEvent e = null;
  1910.         // Process the listeners last to first, notifying
  1911.         // those that are interested in this event
  1912.         for (int i = listeners.length-2; i>=0; i-=2) {
  1913.             if (listeners[i]==TreeExpansionListener.class) {
  1914.                 // Lazily create the event:
  1915.                 if (e == null)
  1916.                     e = new TreeExpansionEvent(this, path);
  1917.                 ((TreeExpansionListener)listeners[i+1]).
  1918.                     treeExpanded(e);
  1919.             }          
  1920.         }
  1921.     }   
  1922.  
  1923.     /**
  1924.      * Notify all listeners that have registered interest for
  1925.      * notification on this event type.  The event instance 
  1926.      * is lazily created using the parameters passed into 
  1927.      * the fire method.
  1928.      *
  1929.      * @param path the TreePath indicating the node that was collapsed
  1930.      * @see EventListenerList
  1931.      */
  1932.     public void fireTreeCollapsed(TreePath path) {
  1933.         // Guaranteed to return a non-null array
  1934.         Object[] listeners = listenerList.getListenerList();
  1935.         TreeExpansionEvent e = null;
  1936.         // Process the listeners last to first, notifying
  1937.         // those that are interested in this event
  1938.         for (int i = listeners.length-2; i>=0; i-=2) {
  1939.             if (listeners[i]==TreeExpansionListener.class) {
  1940.                 // Lazily create the event:
  1941.                 if (e == null)
  1942.                     e = new TreeExpansionEvent(this, path);
  1943.                 ((TreeExpansionListener)listeners[i+1]).
  1944.                     treeCollapsed(e);
  1945.             }          
  1946.         }
  1947.     }   
  1948.  
  1949.     /**
  1950.      * Notify all listeners that have registered interest for
  1951.      * notification on this event type.  The event instance 
  1952.      * is lazily created using the parameters passed into 
  1953.      * the fire method.
  1954.      *
  1955.      * @param path the TreePath indicating the node that was expanded
  1956.      * @see EventListenerList
  1957.      */
  1958.      public void fireTreeWillExpand(TreePath path) throws ExpandVetoException {
  1959.         // Guaranteed to return a non-null array
  1960.         Object[] listeners = listenerList.getListenerList();
  1961.         TreeExpansionEvent e = null;
  1962.         // Process the listeners last to first, notifying
  1963.         // those that are interested in this event
  1964.         for (int i = listeners.length-2; i>=0; i-=2) {
  1965.             if (listeners[i]==TreeWillExpandListener.class) {
  1966.                 // Lazily create the event:
  1967.                 if (e == null)
  1968.                     e = new TreeExpansionEvent(this, path);
  1969.                 ((TreeWillExpandListener)listeners[i+1]).
  1970.                     treeWillExpand(e);
  1971.             }          
  1972.         }
  1973.     }   
  1974.  
  1975.     /**
  1976.      * Notify all listeners that have registered interest for
  1977.      * notification on this event type.  The event instance 
  1978.      * is lazily created using the parameters passed into 
  1979.      * the fire method.
  1980.      *
  1981.      * @param path the TreePath indicating the node that was expanded
  1982.      * @see EventListenerList
  1983.      */
  1984.      public void fireTreeWillCollapse(TreePath path) throws ExpandVetoException {
  1985.         // Guaranteed to return a non-null array
  1986.         Object[] listeners = listenerList.getListenerList();
  1987.         TreeExpansionEvent e = null;
  1988.         // Process the listeners last to first, notifying
  1989.         // those that are interested in this event
  1990.         for (int i = listeners.length-2; i>=0; i-=2) {
  1991.             if (listeners[i]==TreeWillExpandListener.class) {
  1992.                 // Lazily create the event:
  1993.                 if (e == null)
  1994.                     e = new TreeExpansionEvent(this, path);
  1995.                 ((TreeWillExpandListener)listeners[i+1]).
  1996.                     treeWillCollapse(e);
  1997.             }          
  1998.         }
  1999.     }   
  2000.  
  2001.     /**
  2002.      * Adds a listener for TreeSelection events.
  2003.      *
  2004.      * @param tsl the TreeSelectionListener that will be notified when
  2005.      *            a node is selected or deselected (a "negative
  2006.      *            selection")
  2007.      */
  2008.     public void addTreeSelectionListener(TreeSelectionListener tsl) {
  2009.         listenerList.add(TreeSelectionListener.class,tsl);
  2010.         if(listenerList.getListenerCount(TreeSelectionListener.class) != 0
  2011.            && selectionRedirector == null) {
  2012.             selectionRedirector = new TreeSelectionRedirector();
  2013.             selectionModel.addTreeSelectionListener(selectionRedirector);
  2014.         }
  2015.     }
  2016.  
  2017.     /**
  2018.      * Removes a TreeSelection listener.
  2019.      *
  2020.      * @param tsl the TreeSelectionListener to remove
  2021.      */
  2022.     public void removeTreeSelectionListener(TreeSelectionListener tsl) {
  2023.         listenerList.remove(TreeSelectionListener.class,tsl);
  2024.         if(listenerList.getListenerCount(TreeSelectionListener.class) == 0
  2025.            && selectionRedirector != null) {
  2026.             selectionModel.removeTreeSelectionListener
  2027.                 (selectionRedirector);
  2028.             selectionRedirector = null;
  2029.         }
  2030.     }
  2031.  
  2032.     /**
  2033.      * Notify all listeners that have registered interest for
  2034.      * notification on this event type.  The event instance 
  2035.      * is lazily created using the parameters passed into 
  2036.      * the fire method.
  2037.      *
  2038.      * @param e the TreeSelectionEvent generated by the TreeSelectionModel
  2039.      *          when a node is selected or deselected
  2040.      * @see EventListenerList
  2041.      */
  2042.     protected void fireValueChanged(TreeSelectionEvent e) {
  2043.         // Guaranteed to return a non-null array
  2044.         Object[] listeners = listenerList.getListenerList();
  2045.         // Process the listeners last to first, notifying
  2046.         // those that are interested in this event
  2047.         for (int i = listeners.length-2; i>=0; i-=2) {
  2048.             // TreeSelectionEvent e = null;
  2049.             if (listeners[i]==TreeSelectionListener.class) {
  2050.                 // Lazily create the event:
  2051.                 // if (e == null)
  2052.                 // e = new ListSelectionEvent(this, firstIndex, lastIndex);
  2053.                 ((TreeSelectionListener)listeners[i+1]).valueChanged(e);
  2054.             }          
  2055.         }
  2056.     }
  2057.  
  2058.     /**
  2059.      * Sent when the tree has changed enough that we need to resize
  2060.      * the bounds, but not enough that we need to remove the
  2061.      * expanded node set (e.g nodes were expanded or collapsed, or
  2062.      * nodes were inserted into the tree). You should never have to
  2063.      * invoke this, the UI will invoke this as it needs to.
  2064.      */
  2065.     public void treeDidChange() {
  2066.         revalidate();
  2067.         repaint();
  2068.     }
  2069.  
  2070.     /**
  2071.      * Sets the number of rows that are to be displayed.
  2072.      * This will only work if the reciever is contained in a JScrollPane,
  2073.      * and will adjust the preferred size and size of that scrollpane.
  2074.      *
  2075.      * @param newCount the number of rows to display
  2076.      * @beaninfo
  2077.      *        bound: true
  2078.      *  description: The number of rows that are to be displayed.
  2079.      */
  2080.     public void setVisibleRowCount(int newCount) {
  2081.         int                 oldCount = visibleRowCount;
  2082.  
  2083.         visibleRowCount = newCount;
  2084.         firePropertyChange(VISIBLE_ROW_COUNT_PROPERTY, oldCount,
  2085.                            visibleRowCount);
  2086.         invalidate();
  2087.         if (accessibleContext != null) {
  2088.             ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  2089.         }
  2090.     }
  2091.  
  2092.     /**
  2093.      * Returns the number of rows that are displayed in the display area.
  2094.      *
  2095.      * @return the number of rows displayed
  2096.      */
  2097.     public int getVisibleRowCount() {
  2098.         return visibleRowCount;
  2099.     }
  2100.  
  2101.     // Serialization support.  
  2102.     private void writeObject(ObjectOutputStream s) throws IOException {
  2103.         Vector      values = new Vector();
  2104.  
  2105.         s.defaultWriteObject();
  2106.         // Save the cellRenderer, if its Serializable.
  2107.         if(cellRenderer != null && cellRenderer instanceof Serializable) {
  2108.             values.addElement("cellRenderer");
  2109.             values.addElement(cellRenderer);
  2110.         }
  2111.         // Save the cellEditor, if its Serializable.
  2112.         if(cellEditor != null && cellEditor instanceof Serializable) {
  2113.             values.addElement("cellEditor");
  2114.             values.addElement(cellEditor);
  2115.         }
  2116.         // Save the treeModel, if its Serializable.
  2117.         if(treeModel != null && treeModel instanceof Serializable) {
  2118.             values.addElement("treeModel");
  2119.             values.addElement(treeModel);
  2120.         }
  2121.         // Save the selectionModel, if its Serializable.
  2122.         if(selectionModel != null && selectionModel instanceof Serializable) {
  2123.             values.addElement("selectionModel");
  2124.             values.addElement(selectionModel);
  2125.         }
  2126.  
  2127.     Object      expandedData = getArchivableExpandedState();
  2128.  
  2129.     if(expandedData != null) {
  2130.             values.addElement("expandedState");
  2131.             values.addElement(expandedData);
  2132.     }
  2133.  
  2134.         s.writeObject(values);
  2135.     }
  2136.  
  2137.     private void readObject(ObjectInputStream s) 
  2138.         throws IOException, ClassNotFoundException {
  2139.         s.defaultReadObject();
  2140.  
  2141.     // Create an instance of expanded state.
  2142.  
  2143.     expandedState = new Hashtable();
  2144.  
  2145.     expandedStack = new Stack();
  2146.  
  2147.         Vector          values = (Vector)s.readObject();
  2148.         int             indexCounter = 0;
  2149.         int             maxCounter = values.size();
  2150.  
  2151.         if(indexCounter < maxCounter && values.elementAt(indexCounter).
  2152.            equals("cellRenderer")) {
  2153.             cellRenderer = (TreeCellRenderer)values.elementAt(++indexCounter);
  2154.             indexCounter++;
  2155.         }
  2156.         if(indexCounter < maxCounter && values.elementAt(indexCounter).
  2157.            equals("cellEditor")) {
  2158.             cellEditor = (TreeCellEditor)values.elementAt(++indexCounter);
  2159.             indexCounter++;
  2160.         }
  2161.         if(indexCounter < maxCounter && values.elementAt(indexCounter).
  2162.            equals("treeModel")) {
  2163.             treeModel = (TreeModel)values.elementAt(++indexCounter);
  2164.             indexCounter++;
  2165.         }
  2166.         if(indexCounter < maxCounter && values.elementAt(indexCounter).
  2167.            equals("selectionModel")) {
  2168.             selectionModel = (TreeSelectionModel)values.elementAt(++indexCounter);
  2169.             indexCounter++;
  2170.         }
  2171.         if(indexCounter < maxCounter && values.elementAt(indexCounter).
  2172.            equals("expandedState")) {
  2173.         unarchiveExpandedState(values.elementAt(++indexCounter));
  2174.             indexCounter++;
  2175.         }
  2176.     // Reinstall the redirector.
  2177.         if(listenerList.getListenerCount(TreeSelectionListener.class) != 0) {
  2178.             selectionRedirector = new TreeSelectionRedirector();
  2179.             selectionModel.addTreeSelectionListener(selectionRedirector);
  2180.         }
  2181.     // Listener to TreeModel.
  2182.     if(treeModel != null) {
  2183.         treeModelListener = createTreeModelListener();
  2184.         if(treeModelListener != null)
  2185.         treeModel.addTreeModelListener(treeModelListener);
  2186.     }
  2187.  
  2188.     if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  2189.         ui.installUI(this);
  2190.     }
  2191.     }
  2192.  
  2193.     /**
  2194.      * Returns an object that can be archived indicating what nodes are
  2195.      * expanded and what aren't. The objects from the model are NOT
  2196.      * written out.
  2197.      */
  2198.     private Object getArchivableExpandedState() {
  2199.     TreeModel       model = getModel();
  2200.  
  2201.     if(model != null) {
  2202.         Enumeration        paths = expandedState.keys();
  2203.  
  2204.         if(paths != null) {
  2205.         Vector         state = new Vector();
  2206.  
  2207.         while(paths.hasMoreElements()) {
  2208.             TreePath   path = (TreePath)paths.nextElement();
  2209.             Object     archivePath;
  2210.  
  2211.             try {
  2212.             archivePath = getModelIndexsForPath(path);
  2213.             } catch (Error error) {
  2214.             archivePath = null;
  2215.             }
  2216.             if(archivePath != null) {
  2217.             state.addElement(archivePath);
  2218.             state.addElement(expandedState.get(path));
  2219.             }
  2220.         }
  2221.         return state;
  2222.         }
  2223.     }
  2224.     return null;
  2225.     }
  2226.  
  2227.     /**
  2228.      * Updates the expanded state of nodes in the tree based on the 
  2229.      * previously archived state <code>state</code>.
  2230.      */
  2231.     private void unarchiveExpandedState(Object state) {
  2232.     if(state instanceof Vector) {
  2233.         Vector          paths = (Vector)state;
  2234.  
  2235.         for(int counter = paths.size() - 1; counter >= 0; counter--) {
  2236.         Boolean        eState = (Boolean)paths.elementAt(counter--);
  2237.         TreePath       path;
  2238.  
  2239.         try {
  2240.             path = getPathForIndexs((int[])paths.elementAt(counter));
  2241.             if(path != null)
  2242.             expandedState.put(path, eState);
  2243.         } catch (Error error) {}
  2244.         }
  2245.     }
  2246.     }
  2247.  
  2248.     /**
  2249.      * Returns an array of integers specifying the indexs of the
  2250.      * components in the <code>path</code>. If <code>path</code> is
  2251.      * the root, this will return an empty array.
  2252.      */
  2253.     private int[] getModelIndexsForPath(TreePath path) {
  2254.     if(path != null) {
  2255.         TreeModel   model = getModel();
  2256.         int         count = path.getPathCount();
  2257.         int[]       indexs = new int[count - 1];
  2258.         Object      parent = model.getRoot();
  2259.  
  2260.         for(int counter = 1; counter < count; counter++) {
  2261.         indexs[counter - 1] = model.getIndexOfChild
  2262.                        (parent, path.getPathComponent(counter));
  2263.         parent = path.getPathComponent(counter);
  2264.         if(indexs[counter - 1] < 0)
  2265.             return null;
  2266.         }
  2267.         return indexs;
  2268.     }
  2269.     return null;
  2270.     }
  2271.  
  2272.     /**
  2273.      * Returns a TreePath created by obtaining the children for each of
  2274.      * the indices in <code>indexs</code>.
  2275.      */
  2276.     private TreePath getPathForIndexs(int[] indexs) {
  2277.     if(indexs == null)
  2278.         return null;
  2279.  
  2280.     TreeModel    model = getModel();
  2281.  
  2282.     if(model == null)
  2283.         return null;
  2284.  
  2285.     int          count = indexs.length;
  2286.     Object       parent = model.getRoot();
  2287.     TreePath     parentPath = new TreePath(parent);
  2288.  
  2289.     for(int counter = 0; counter < count; counter++) {
  2290.         parent = model.getChild(parent, indexs[counter]);
  2291.         if(parent == null)
  2292.         return null;
  2293.         parentPath = parentPath.pathByAddingChild(parent);
  2294.     }
  2295.     return parentPath;
  2296.     }
  2297.  
  2298.     /**
  2299.      * EmptySelectionModel is a TreeSelectionModel that does not allow
  2300.      * anything to be selected.
  2301.      * <p>
  2302.      * <strong>Warning:</strong>
  2303.      * Serialized objects of this class will not be compatible with
  2304.      * future Swing releases.  The current serialization support is appropriate
  2305.      * for short term storage or RMI between applications running the same
  2306.      * version of Swing.  A future release of Swing will provide support for
  2307.      * long term persistence.
  2308.      */
  2309.     protected static class EmptySelectionModel extends
  2310.               DefaultTreeSelectionModel
  2311.     {
  2312.         /** Unique shared instance. */
  2313.         protected static final EmptySelectionModel sharedInstance =
  2314.             new EmptySelectionModel();
  2315.  
  2316.         /** Returns a shared instance of an empty selection model */
  2317.         static public EmptySelectionModel sharedInstance() {
  2318.             return sharedInstance;
  2319.         }
  2320.  
  2321.         /** A null implementation that selects nothing */
  2322.         public void setSelectionPaths(TreePath[] pPaths) {}
  2323.         /** A null implementation that adds nothing */
  2324.         public void addSelectionPaths(TreePath[] paths) {}
  2325.         /** A null implementation that removes nothing */
  2326.         public void removeSelectionPaths(TreePath[] paths) {}
  2327.     }
  2328.  
  2329.  
  2330.     /**
  2331.      * Handles creating a new TreeSelectionEvent with the JTree as the
  2332.      * source and passing it off to all the listeners.
  2333.      * <p>
  2334.      * <strong>Warning:</strong>
  2335.      * Serialized objects of this class will not be compatible with
  2336.      * future Swing releases.  The current serialization support is appropriate
  2337.      * for short term storage or RMI between applications running the same
  2338.      * version of Swing.  A future release of Swing will provide support for
  2339.      * long term persistence.
  2340.      */
  2341.     protected class TreeSelectionRedirector implements Serializable,
  2342.                     TreeSelectionListener
  2343.     {
  2344.         /**
  2345.          * Invoked by the TreeSelectionModel when the selection changes.
  2346.          * 
  2347.          * @param e the TreeSelectionEvent generated by the TreeSelectionModel
  2348.          */
  2349.         public void valueChanged(TreeSelectionEvent e) {
  2350.             TreeSelectionEvent       newE;
  2351.  
  2352.             newE = (TreeSelectionEvent)e.cloneWithSource(JTree.this);
  2353.             fireValueChanged(newE);
  2354.         }
  2355.     } // End of class JTree.TreeSelectionRedirector
  2356.  
  2357.     //
  2358.     // Scrollable interface
  2359.     //
  2360.  
  2361.     /**
  2362.      * Returns the preferred display size of a JTree. The height is
  2363.      * determined from <code>getVisibleRowCount</code> and the width
  2364.      * is the current preferred width.
  2365.      *
  2366.      * @return a Dimension object containing the preferred size
  2367.      */
  2368.     public Dimension getPreferredScrollableViewportSize() {
  2369.         int                 width = getPreferredSize().width;
  2370.         int                 visRows = getVisibleRowCount();
  2371.         int                 height;
  2372.  
  2373.         if(isFixedRowHeight())
  2374.             height = visRows * getRowHeight();
  2375.         else {
  2376.             TreeUI          ui = getUI();
  2377.  
  2378.             if(ui != null && ui.getRowCount(this) > 0)
  2379.                 height = getRowBounds(0).height * visRows;
  2380.             else
  2381.                 height = 16 * visRows;
  2382.         }
  2383.         return new Dimension(width, height);
  2384.     }
  2385.  
  2386.     /**
  2387.      * Returns the amount to increment when scrolling. The amount is
  2388.      * the height of the first displayed row that isn't completely in view
  2389.      * or, if it is totally displayed, the height of the next row in the
  2390.      * scrolling direction.
  2391.      * 
  2392.      * @param visibleRect The view area visible within the viewport
  2393.      * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
  2394.      * @param direction Less than zero to scroll up/left, greater than zero for down/right.
  2395.      * @return The "unit" increment for scrolling in the specified direction
  2396.      * @see JScrollBar#setUnitIncrement
  2397.      */
  2398.     public int getScrollableUnitIncrement(Rectangle visibleRect,
  2399.                                           int orientation, int direction) {
  2400.         if(orientation == SwingConstants.VERTICAL) {
  2401.             Rectangle       rowBounds;
  2402.             int             firstIndex = getClosestRowForLocation
  2403.                                          (0, visibleRect.y);
  2404.  
  2405.             if(firstIndex != -1) {
  2406.                 rowBounds = getRowBounds(firstIndex);
  2407.                 if(rowBounds.y != visibleRect.y) {
  2408.                     if(direction < 0) // UP
  2409.                         return (visibleRect.y - rowBounds.y);
  2410.                     return (rowBounds.y + rowBounds.height - visibleRect.y);
  2411.                 }
  2412.                 if(direction < 0) { // UP
  2413.                     if(firstIndex != 0) {
  2414.                         rowBounds = getRowBounds(firstIndex - 1);
  2415.                         return rowBounds.height;
  2416.                     }
  2417.                 }
  2418.                 else {
  2419.                     return rowBounds.height;
  2420.                 }
  2421.             }
  2422.             return 0;
  2423.         }
  2424.         return 4;
  2425.     }
  2426.  
  2427.  
  2428.     /**
  2429.      * Returns the amount for a block inrecment, which is the height or
  2430.      * width of <code>visibleRect</code>, based on <code>orientation</code>.
  2431.      * 
  2432.      * @param visibleRect The view area visible within the viewport
  2433.      * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
  2434.      * @param direction Less than zero to scroll up/left, greater than zero for down/right.
  2435.      * @return The "block" increment for scrolling in the specified direction.
  2436.      * @see JScrollBar#setBlockIncrement
  2437.      */
  2438.     public int getScrollableBlockIncrement(Rectangle visibleRect,
  2439.                                            int orientation, int direction) {
  2440.         return (orientation == SwingConstants.VERTICAL) ? visibleRect.height :
  2441.             visibleRect.width;
  2442.     }
  2443.     
  2444.     /**
  2445.      * Returns false to indicate that the width of the viewport does not 
  2446.      * determine the width of the table, unless the preferred width of 
  2447.      * the tree is smaller than the viewports width.  In other words: 
  2448.      * ensure that the tree is never smaller than its viewport.
  2449.      * 
  2450.      * @return false
  2451.      * @see Scrollable#getScrollableTracksViewportWidth
  2452.      */
  2453.     public boolean getScrollableTracksViewportWidth() {
  2454.     if (getParent() instanceof JViewport) {
  2455.         return (((JViewport)getParent()).getWidth() > getPreferredSize().width);
  2456.     }
  2457.     return false;
  2458.     }
  2459.  
  2460.     /**
  2461.      * Returns false to indicate that the height of the viewport does not 
  2462.      * determine the height of the table, unless the preferred height
  2463.      * of the tree is smaller than the viewports height.  In other words: 
  2464.      * ensure that the tree is never smaller than its viewport.
  2465.      * 
  2466.      * @return false
  2467.      * @see Scrollable#getScrollableTracksViewportHeight
  2468.      */
  2469.     public boolean getScrollableTracksViewportHeight() {
  2470.     if (getParent() instanceof JViewport) {
  2471.         return (((JViewport)getParent()).getHeight() > getPreferredSize().height);
  2472.     }
  2473.     return false;
  2474.     }
  2475.  
  2476.     /**
  2477.      * Sets the expanded state of the receiver. If <code>state</code> is
  2478.      * true, all parents of <code>path</code> and path are marked as
  2479.      * expanded. If <code>state</code> is false, all parents of 
  2480.      * <code>path</code> are marked EXPANDED, but <code>path</code> itself
  2481.      * is marked collapsed.<p>
  2482.      * This will fail if a TreeWillExpandListener vetos it.
  2483.      */
  2484.     protected void setExpandedState(TreePath path, boolean state) {
  2485.     if(path != null) {
  2486.         // Make sure all parents of path are expanded.
  2487.         Stack         stack;
  2488.         TreePath      parentPath = path.getParentPath();
  2489.  
  2490.         if (expandedStack.size() == 0) {
  2491.         stack = new Stack();
  2492.         }
  2493.         else {
  2494.         stack = (Stack)expandedStack.pop();
  2495.         }
  2496.  
  2497.         try {
  2498.         while(parentPath != null) {
  2499.             if(isExpanded(parentPath)) {
  2500.             parentPath = null;
  2501.             }
  2502.             else {
  2503.             stack.push(parentPath);
  2504.             parentPath = parentPath.getParentPath();
  2505.             }
  2506.         }
  2507.         for(int counter = stack.size() - 1; counter >= 0; counter--) {
  2508.             parentPath = (TreePath)stack.pop();
  2509.             if(!isExpanded(parentPath)) {
  2510.             try {
  2511.                 fireTreeWillExpand(parentPath);
  2512.             } catch (ExpandVetoException eve) {
  2513.                 // Expand vetoed!
  2514.                 return;
  2515.             }
  2516.             expandedState.put(parentPath, Boolean.TRUE);
  2517.             fireTreeExpanded(parentPath);
  2518.             if (accessibleContext != null) {
  2519.                 ((AccessibleJTree)accessibleContext).
  2520.                                   fireVisibleDataPropertyChange();
  2521.             }
  2522.             }
  2523.         }
  2524.         }
  2525.         finally {
  2526.         if (expandedStack.size() < TEMP_STACK_SIZE) {
  2527.             stack.removeAllElements();
  2528.             expandedStack.push(stack);
  2529.         }
  2530.         }
  2531.         if(!state) {
  2532.         // collapse last path.
  2533.         Object          cValue = expandedState.get(path);
  2534.  
  2535.         if(cValue != null && ((Boolean)cValue).booleanValue()) {
  2536.             try {
  2537.             fireTreeWillCollapse(path);
  2538.             }
  2539.             catch (ExpandVetoException eve) {
  2540.             return;
  2541.             }
  2542.             expandedState.put(path, Boolean.FALSE);
  2543.             fireTreeCollapsed(path);
  2544.             if (accessibleContext != null) {
  2545.             ((AccessibleJTree)accessibleContext).
  2546.                         fireVisibleDataPropertyChange();
  2547.             }
  2548.         }
  2549.         }
  2550.         else {
  2551.         // Expand last path.
  2552.         Object          cValue = expandedState.get(path);
  2553.  
  2554.         if(cValue == null || !((Boolean)cValue).booleanValue()) {
  2555.             try {
  2556.             fireTreeWillExpand(path);
  2557.             }
  2558.             catch (ExpandVetoException eve) {
  2559.             return;
  2560.             }
  2561.             expandedState.put(path, Boolean.TRUE);
  2562.             fireTreeExpanded(path);
  2563.             if (accessibleContext != null) {
  2564.             ((AccessibleJTree)accessibleContext).
  2565.                               fireVisibleDataPropertyChange();
  2566.             }
  2567.         }
  2568.         }
  2569.     }
  2570.     }
  2571.  
  2572.     /**
  2573.      * Returns an Enumeration of TreePaths that have been expanded that
  2574.      * are descendants of <code>parent</code>.
  2575.      */
  2576.     protected Enumeration getDescendantToggledPaths(TreePath parent) {
  2577.     if(parent == null)
  2578.         return null;
  2579.  
  2580.     Vector            descendants = new Vector();
  2581.     Enumeration       nodes = expandedState.keys();
  2582.     TreePath          path;
  2583.  
  2584.     while(nodes.hasMoreElements()) {
  2585.         path = (TreePath)nodes.nextElement();
  2586.         if(parent.isDescendant(path))
  2587.         descendants.addElement(path);
  2588.     }
  2589.     return descendants.elements();
  2590.     }
  2591.     
  2592.     /**
  2593.      * Removes any descendants of the TreePaths in <code>toRemove</code>
  2594.      * that have been expanded.
  2595.      */
  2596.      protected void removeDescendantToggledPaths(Enumeration toRemove) {
  2597.      if(toRemove != null) {
  2598.          while(toRemove.hasMoreElements()) {
  2599.          Enumeration         descendants = getDescendantToggledPaths
  2600.                                  ((TreePath)toRemove.nextElement());
  2601.  
  2602.          if(descendants != null) {
  2603.              while(descendants.hasMoreElements()) {
  2604.              expandedState.remove(descendants.nextElement());
  2605.              }
  2606.          }
  2607.          }
  2608.      }
  2609.      }
  2610.  
  2611.      /**
  2612.       * Clears the cache of toggled tree paths. This does NOT send out
  2613.       * any TreeExpansionListener events.
  2614.       */
  2615.      protected void clearToggledPaths() {
  2616.      expandedState.clear();
  2617.      }
  2618.  
  2619.      /**
  2620.       * Creates and returns an instance of TreeModelHandler. The returned
  2621.       * object is responsible for updating the expanded state when the
  2622.       * TreeModel changes.
  2623.       */
  2624.      protected TreeModelListener createTreeModelListener() {
  2625.      return new TreeModelHandler();
  2626.      }
  2627.  
  2628.  
  2629.      /**
  2630.       * Listens to the model and updates the expandedState accordingly
  2631.       * when nodes are removed, or changed.
  2632.       */
  2633.     protected class TreeModelHandler implements TreeModelListener {
  2634.     public void treeNodesChanged(TreeModelEvent e) { }
  2635.  
  2636.     public void treeNodesInserted(TreeModelEvent e) { }
  2637.  
  2638.     public void treeStructureChanged(TreeModelEvent e) {
  2639.         if(e == null)
  2640.         return;
  2641.  
  2642.         // NOTE: If I change this to NOT remove the descendants
  2643.         // and update BasicTreeUIs treeStructureChanged method
  2644.         // to update descendants in response to a treeStructureChanged
  2645.         // event, all the children of the event won't collapse!
  2646.         TreePath            parent = e.getTreePath();
  2647.  
  2648.         if(parent == null)
  2649.         return;
  2650.  
  2651.         if(expandedState.get(parent) != null) {
  2652.         Vector              toRemove = new Vector(1);
  2653.         boolean             isExpanded = isExpanded(parent);
  2654.  
  2655.         toRemove.addElement(parent);
  2656.         removeDescendantToggledPaths(toRemove.elements());
  2657.         if(isExpanded) {
  2658.             TreeModel         model = getModel();
  2659.  
  2660.             if(model == null || model.isLeaf
  2661.                (parent.getLastPathComponent()))
  2662.             collapsePath(parent);
  2663.             else
  2664.             expandedState.put(parent, Boolean.TRUE);
  2665.         }
  2666.         }
  2667.     }
  2668.  
  2669.     public void treeNodesRemoved(TreeModelEvent e) {
  2670.         if(e == null)
  2671.         return;
  2672.  
  2673.         TreePath            parent = e.getTreePath();
  2674.         Object[]            children = e.getChildren();
  2675.  
  2676.         if(children == null)
  2677.         return;
  2678.  
  2679.         TreePath            rPath;
  2680.         Vector              toRemove = new Vector(Math.max
  2681.                               (1, children.length));
  2682.  
  2683.         for(int counter = children.length - 1; counter >= 0; counter--) {
  2684.         rPath = parent.pathByAddingChild(children[counter]);
  2685.         if(expandedState.get(rPath) != null)
  2686.             toRemove.addElement(rPath);
  2687.         }
  2688.         if(toRemove.size() > 0)
  2689.         removeDescendantToggledPaths(toRemove.elements());
  2690.  
  2691.         TreeModel         model = getModel();
  2692.  
  2693.         if(model == null || model.isLeaf(parent.getLastPathComponent()))
  2694.         expandedState.remove(parent);
  2695.     }
  2696.     }
  2697.  
  2698.  
  2699.     /**
  2700.      * DynamicUtilTreeNode can wrap vectors/hashtables/arrays/strings and
  2701.      * create the appropriate children tree nodes as necessary. It is
  2702.      * dynamic in that it'll only create the children as necessary.
  2703.      * <p>
  2704.      * <strong>Warning:</strong>
  2705.      * Serialized objects of this class will not be compatible with
  2706.      * future Swing releases.  The current serialization support is appropriate
  2707.      * for short term storage or RMI between applications running the same
  2708.      * version of Swing.  A future release of Swing will provide support for
  2709.      * long term persistence.
  2710.      */
  2711.     public static class DynamicUtilTreeNode extends DefaultMutableTreeNode {
  2712.         /* Does the receiver have children? */
  2713.         protected boolean            hasChildren;
  2714.         /** Value to create children with. */
  2715.         protected Object             childValue;
  2716.         /* Have the children been loaded yet? */
  2717.         protected boolean            loadedChildren;
  2718.  
  2719.         /**
  2720.          * Adds to parent all the children in <code>children</code>.
  2721.          * If <code>children</code> is an array or Vector all of its
  2722.          * elements are added is children, otherwise if <code>children</code>
  2723.          * is a Hashtable all the key/value pairs are added in the order
  2724.          * Enumeration returns them.
  2725.          */
  2726.         public static void createChildren(DefaultMutableTreeNode parent,
  2727.                                           Object children) {
  2728.             if(children instanceof Vector) {
  2729.                 Vector          childVector = (Vector)children;
  2730.  
  2731.                 for(int counter = 0, maxCounter = childVector.size();
  2732.                     counter < maxCounter; counter++)
  2733.                     parent.add(new DynamicUtilTreeNode
  2734.                                (childVector.elementAt(counter),
  2735.                                 childVector.elementAt(counter)));
  2736.             }
  2737.             else if(children instanceof Hashtable) {
  2738.                 Hashtable           childHT = (Hashtable)children;
  2739.                 Enumeration         keys = childHT.keys();
  2740.                 Object              aKey;
  2741.  
  2742.                 while(keys.hasMoreElements()) {
  2743.                     aKey = keys.nextElement();
  2744.                     parent.add(new DynamicUtilTreeNode(aKey,
  2745.                                                        childHT.get(aKey)));
  2746.                 }
  2747.             }
  2748.             else if(children instanceof Object[]) {
  2749.                 Object[]             childArray = (Object[])children;
  2750.  
  2751.                 for(int counter = 0, maxCounter = childArray.length;
  2752.                     counter < maxCounter; counter++)
  2753.                     parent.add(new DynamicUtilTreeNode(childArray[counter],
  2754.                                                        childArray[counter]));
  2755.             }
  2756.         }
  2757.  
  2758.         /**
  2759.          * Creates a node with the specified object as its value and
  2760.          * with the specified children. For the node to allow children,
  2761.          * the children-object must be an array of objects, a Vector,
  2762.          * or a Hashtable -- even if empty. Otherwise, the node is not
  2763.          * allowed to have children.
  2764.          *
  2765.          * @param value  the Object that is the value for the new node
  2766.          * @param children an array of Objects, a Vector, or a Hashtable
  2767.          *                 used to create the child nodes. If any other
  2768.          *                 object is specified, or if the value is null,
  2769.          *                 then the node is not allowed to have children.
  2770.          */
  2771.         public DynamicUtilTreeNode(Object value, Object children) {
  2772.             super(value);
  2773.             loadedChildren = false;
  2774.             childValue = children;
  2775.             if(children != null) {
  2776.                 if(children instanceof Vector)
  2777.                     setAllowsChildren(true);
  2778.                 else if(children instanceof Hashtable)
  2779.                     setAllowsChildren(true);
  2780.                 else if(children instanceof Object[])
  2781.                     setAllowsChildren(true);
  2782.                 else
  2783.                     setAllowsChildren(false);
  2784.             }
  2785.             else
  2786.                 setAllowsChildren(false);
  2787.         }
  2788.  
  2789.         /**
  2790.          * Returns true if this node allows children. Whether the node
  2791.          * allows children depends on how it was created.
  2792.          *
  2793.          * @return true if this node allows children, false otherwise.
  2794.          * @see JTree.DynamicUtilTreeNode#DynamicUtilTreeNode(Object, Object)
  2795.          */
  2796.         public boolean isLeaf() {
  2797.             return !getAllowsChildren();
  2798.         }
  2799.  
  2800.         /**
  2801.          * Returns the number of child nodes.
  2802.          *
  2803.          * @return the number of child nodes
  2804.          */
  2805.         public int getChildCount() {
  2806.             if(!loadedChildren)
  2807.                 loadChildren();
  2808.             return super.getChildCount();
  2809.         }
  2810.  
  2811.         /**
  2812.          * Loads the children based on childValue. If childValue is
  2813.          * a Vector orarray each element  added as a child, if childValue
  2814.          * is a Hashtable each key/value pair is added in the order that
  2815.          * Enumeration returns the keys.
  2816.          */
  2817.         protected void loadChildren() {
  2818.             loadedChildren = true;
  2819.             createChildren(this, childValue);
  2820.         }
  2821.  
  2822.     /**
  2823.      * Subclassed to load the children, if necessary.
  2824.      */
  2825.     public TreeNode getChildAt(int index) {
  2826.         if(!loadedChildren)
  2827.         loadChildren();
  2828.         return super.getChildAt(index);
  2829.     }
  2830.  
  2831.     /**
  2832.      * Subclassed to load the children, if necessary.
  2833.      */
  2834.     public Enumeration children() {
  2835.         if(!loadedChildren)
  2836.         loadChildren();
  2837.         return super.children();
  2838.     }
  2839.     }
  2840.  
  2841.  
  2842.     /**
  2843.      * Returns a string representation of this JTree. This method 
  2844.      * is intended to be used only for debugging purposes, and the 
  2845.      * content and format of the returned string may vary between      
  2846.      * implementations. The returned string may be empty but may not 
  2847.      * be <code>null</code>.
  2848.      * <P>
  2849.      * Overriding paramString() to provide information about the
  2850.      * specific new aspects of the JFC components.
  2851.      * 
  2852.      * @return  a string representation of this JTree.
  2853.      */
  2854.     protected String paramString() {
  2855.         String rootVisibleString = (rootVisible ?
  2856.                                     "true" : "false");
  2857.         String showsRootHandlesString = (showsRootHandles ?
  2858.                      "true" : "false");
  2859.         String editableString = (editable ?
  2860.                  "true" : "false");
  2861.         String largeModelString = (largeModel ?
  2862.                    "true" : "false");
  2863.         String invokesStopCellEditingString = (invokesStopCellEditing ?
  2864.                            "true" : "false");
  2865.         String scrollsOnExpandString = (scrollsOnExpand ?
  2866.                     "true" : "false");
  2867.  
  2868.         return super.paramString() +
  2869.         ",editable=" + editableString +
  2870.         ",invokesStopCellEditing=" + invokesStopCellEditingString +
  2871.         ",largeModel=" + largeModelString +
  2872.         ",rootVisible=" + rootVisibleString +
  2873.         ",rowHeight=" + rowHeight +
  2874.         ",scrollsOnExpand=" + scrollsOnExpandString +
  2875.         ",showsRootHandles=" + showsRootHandlesString +
  2876.         ",toggleClickCount=" + toggleClickCount +
  2877.         ",visibleRowCount=" + visibleRowCount;
  2878.     }
  2879.  
  2880. /////////////////
  2881. // Accessibility support
  2882. ////////////////
  2883.  
  2884.     /**
  2885.      * Get the AccessibleContext associated with this JComponent
  2886.      *
  2887.      * @return the AccessibleContext of this JComponent
  2888.      */
  2889.     public AccessibleContext getAccessibleContext() {
  2890.         if (accessibleContext == null) {
  2891.             accessibleContext = new AccessibleJTree();
  2892.         }
  2893.         return accessibleContext;
  2894.     }
  2895.  
  2896.     /**
  2897.      * The class used to obtain the accessible role for this object.
  2898.      * <p>
  2899.      * <strong>Warning:</strong>
  2900.      * Serialized objects of this class will not be compatible with
  2901.      * future Swing releases.  The current serialization support is appropriate
  2902.      * for short term storage or RMI between applications running the same
  2903.      * version of Swing.  A future release of Swing will provide support for
  2904.      * long term persistence.
  2905.      */
  2906.     protected class AccessibleJTree extends AccessibleJComponent 
  2907.             implements AccessibleSelection, TreeSelectionListener, 
  2908.                    TreeModelListener, TreeExpansionListener  {
  2909.  
  2910.         TreePath   leadSelectionPath;
  2911.     Accessible leadSelectionAccessible;
  2912.  
  2913.         public AccessibleJTree() {
  2914.             // Add a tree model listener for JTree
  2915.              JTree.this.getModel().addTreeModelListener(this);
  2916.         JTree.this.addTreeExpansionListener(this);      
  2917.         JTree.this.addTreeSelectionListener(this);      
  2918.             leadSelectionPath = JTree.this.getLeadSelectionPath();
  2919.         leadSelectionAccessible = (leadSelectionPath != null) 
  2920.             ? new AccessibleJTreeNode(JTree.this,
  2921.                                       leadSelectionPath,
  2922.                                       JTree.this)
  2923.             : null;
  2924.         }
  2925.  
  2926.         /**
  2927.          * Tree Selection Listener value change method. Used to fire the 
  2928.      * property change
  2929.          *
  2930.          * @param e ListSelectionEvent
  2931.          *
  2932.          */
  2933.         public void valueChanged(TreeSelectionEvent e) {
  2934.         TreePath oldLeadSelectionPath = leadSelectionPath;
  2935.             leadSelectionPath = JTree.this.getLeadSelectionPath();
  2936.         if (oldLeadSelectionPath != leadSelectionPath) {
  2937.         Accessible oldLSA = leadSelectionAccessible;
  2938.         leadSelectionAccessible = (leadSelectionPath != null) 
  2939.             ? new AccessibleJTreeNode(JTree.this,
  2940.                           leadSelectionPath,
  2941.                                     JTree.this)
  2942.             : null;
  2943.                 firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
  2944.                                    oldLSA, leadSelectionAccessible);
  2945.         }
  2946.             firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
  2947.                                new Boolean(false), new Boolean(true));
  2948.     }
  2949.  
  2950.         /**
  2951.          * Fire a visible data property change notification.
  2952.          * A 'visible' data property is that it represents
  2953.          * something about the way the component appears on the
  2954.          * display, where that appearance isn't bound to any other
  2955.          * property. It notifies screen readers  that the visual 
  2956.          * appearance of the component has changed, so they can 
  2957.          * notify the user.
  2958.          */
  2959.         public void fireVisibleDataPropertyChange() {
  2960.            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2961.                               new Boolean(false), new Boolean(true));
  2962.         }
  2963.  
  2964.         // Fire the visible data changes for the model changes.
  2965.  
  2966.         /**
  2967.          * Tree Model Node change notification.
  2968.          *
  2969.          * @param e  a Tree Model event
  2970.          */
  2971.         public void treeNodesChanged(TreeModelEvent e) {
  2972.            fireVisibleDataPropertyChange();
  2973.         }
  2974.  
  2975.         /**
  2976.          * Tree Model Node change notification.
  2977.          *
  2978.          * @param e  a Tree node insertion event
  2979.          */
  2980.         public void treeNodesInserted(TreeModelEvent e) {
  2981.            fireVisibleDataPropertyChange();
  2982.         }
  2983.  
  2984.         /**
  2985.          * Tree Model Node change notification.
  2986.          *
  2987.          * @param e  a Tree node(s) removal event
  2988.          */
  2989.         public  void treeNodesRemoved(TreeModelEvent e) {
  2990.            fireVisibleDataPropertyChange();
  2991.         }
  2992.  
  2993.         /**
  2994.          * Tree Model structure change change notification.
  2995.          *
  2996.          * @param e  a Tree Model event
  2997.          */
  2998.         public  void treeStructureChanged(TreeModelEvent e) {
  2999.            fireVisibleDataPropertyChange();
  3000.         }
  3001.  
  3002.         /**
  3003.          * Tree Collapsed notification.
  3004.          *
  3005.          * @param e  a TreeExpansionEvent
  3006.          */
  3007.         public  void treeCollapsed(TreeExpansionEvent e) {
  3008.            fireVisibleDataPropertyChange();
  3009.         }
  3010.  
  3011.         /**
  3012.          * Tree Model Expansion notification.
  3013.          *
  3014.          * @param e  a Tree node insertion event
  3015.          */
  3016.         public  void treeExpanded(TreeExpansionEvent e) {
  3017.             fireVisibleDataPropertyChange();
  3018.          }
  3019.  
  3020.  
  3021.         private AccessibleContext getCurrentAccessibleContext() {
  3022.             Component c = getCurrentComponent();
  3023.             if (c instanceof Accessible) {
  3024.                 return (((Accessible) c).getAccessibleContext());
  3025.             } else {
  3026.                 return null;
  3027.             }
  3028.         }
  3029.  
  3030.         private Component getCurrentComponent() {
  3031.             // is the object visible?
  3032.             // if so, get row, selected, focus & leaf state, 
  3033.             // and then get the renderer component and return it
  3034.             TreeModel model = JTree.this.getModel();
  3035.             TreePath path = new TreePath(model.getRoot());
  3036.             if (JTree.this.isVisible(path)) {
  3037.                 TreeCellRenderer r = JTree.this.getCellRenderer();
  3038.                 TreeUI ui = JTree.this.getUI();
  3039.                 if (ui != null) {
  3040.                     int row = ui.getRowForPath(JTree.this, path);
  3041.             int lsr = JTree.this.getLeadSelectionRow();
  3042.                     boolean hasFocus = JTree.this.hasFocus()
  3043.                        && (lsr == row);
  3044.                     boolean selected = JTree.this.isPathSelected(path);
  3045.                     boolean expanded = JTree.this.isExpanded(path);
  3046.  
  3047.                     return r.getTreeCellRendererComponent(JTree.this, 
  3048.                         model.getRoot(), selected, expanded, 
  3049.                         model.isLeaf(model.getRoot()), row, hasFocus);
  3050.                 }
  3051.             } 
  3052.             return null;
  3053.         }
  3054.  
  3055.         // Overridden methods from AccessibleJComponent
  3056.  
  3057.         /**
  3058.          * Get the role of this object.
  3059.          *
  3060.          * @return an instance of AccessibleRole describing the role of the 
  3061.          * object
  3062.          * @see AccessibleRole
  3063.          */
  3064.         public AccessibleRole getAccessibleRole() {
  3065.             return AccessibleRole.TREE;
  3066.         }
  3067.  
  3068.         /**
  3069.          * Returns the Accessible child, if one exists, contained at the local
  3070.          * coordinate Point.
  3071.          *
  3072.          * @param p point in local coordinates of the this Accessible
  3073.          * @return the Accessible, if it exists, at the specified location;
  3074.          * else null
  3075.          */
  3076.         public Accessible getAccessibleAt(Point p) {
  3077.             TreePath path = getClosestPathForLocation(p.x, p.y);
  3078.             if (path != null) {
  3079.                 return new AccessibleJTreeNode(JTree.this, path, JTree.this);
  3080.             } else {
  3081.                 return null;
  3082.             }
  3083.         }
  3084.  
  3085.         /**
  3086.          * Returns the number of top-level children nodes of this 
  3087.          * JTree.  Each of these nodes may in turn have children nodes.
  3088.          *
  3089.          * @return the number of accessible children nodes in the tree.
  3090.          */
  3091.         public int getAccessibleChildrenCount() {
  3092.         TreeModel model = JTree.this.getModel();
  3093.         if (model != null) {
  3094.         return 1;
  3095.         } else {
  3096.         return 0;
  3097.         }
  3098.         }
  3099.  
  3100.         /**
  3101.          * Return the nth Accessible child of the object.
  3102.          *
  3103.          * @param i zero-based index of child
  3104.          * @return the nth Accessible child of the object
  3105.          */
  3106.         public Accessible getAccessibleChild(int i) {
  3107.             TreeModel model = JTree.this.getModel();
  3108.             if (model != null) {
  3109.                 if (i != 0) {
  3110.                     return null;
  3111.                 } else {
  3112.                     Object[] objPath = {model.getRoot()};
  3113.                     TreePath path = new TreePath(objPath);
  3114.                     return new AccessibleJTreeNode(JTree.this, path, JTree.this);
  3115.                 }
  3116.             }
  3117.             return null;
  3118.         }
  3119.  
  3120.         /**
  3121.          * Get the index of this object in its accessible parent. 
  3122.          *
  3123.          * @return the index of this object in its parent; -1 if this 
  3124.          * object does not have an accessible parent.
  3125.          * @see #getAccessibleParent
  3126.          */
  3127.         public int getAccessibleIndexInParent() {
  3128.             return 0;
  3129.     }
  3130.  
  3131.         // AccessibleSelection methods
  3132.  
  3133.         public AccessibleSelection getAccessibleSelection() {
  3134.             return this;
  3135.         }
  3136.  
  3137.         /**
  3138.          * Returns the number of items currently selected.
  3139.          * If no items are selected, the return value will be 0.
  3140.          *
  3141.          * @return the number of items currently selected.
  3142.          */
  3143.         public int getAccessibleSelectionCount() {
  3144.             return JTree.this.getSelectionCount();
  3145.         }
  3146.  
  3147.         /**
  3148.          * Returns an Accessible representing the specified selected item
  3149.          * in the object.  If there isn't a selection, or there are 
  3150.          * fewer items selcted than the integer passed in, the return
  3151.          * value will be null.
  3152.          *
  3153.          * @param i the zero-based index of selected items
  3154.          * @return an Accessible containing the selected item
  3155.          */
  3156.         public Accessible getAccessibleSelection(int i) {
  3157.             TreePath[] paths = JTree.this.getSelectionPaths();
  3158.             if (i < 0 || i >= paths.length) {
  3159.                 return null;
  3160.             } else {
  3161.                 return new AccessibleJTreeNode(JTree.this, paths[i], JTree.this);
  3162.             }
  3163.         }
  3164.  
  3165.         /**
  3166.          * Returns true if the current child of this object is selected.
  3167.          *
  3168.          * @param i the zero-based index of the child in this Accessible object.
  3169.          * @see AccessibleContext#getAccessibleChild
  3170.          */
  3171.         public boolean isAccessibleChildSelected(int i) {
  3172.             TreePath[] paths = JTree.this.getSelectionPaths();
  3173.             TreeModel treeModel = JTree.this.getModel();
  3174.             Object o;
  3175.             for (int j = 0; j < paths.length; j++) {
  3176.                 o = paths[j].getLastPathComponent();
  3177.                 if (i == treeModel.getIndexOfChild(treeModel.getRoot(), o)) {
  3178.                     return true;
  3179.                 }
  3180.             }
  3181.             return false;
  3182.         }
  3183.  
  3184.         /**
  3185.          * Adds the specified selected item in the object to the object's
  3186.          * selection.  If the object supports multiple selections,
  3187.          * the specified item is added to any existing selection, otherwise
  3188.          * it replaces any existing selection in the object.  If the
  3189.          * specified item is already selected, this method has no effect.
  3190.          *
  3191.          * @param i the zero-based index of selectable items
  3192.          */
  3193.         public void addAccessibleSelection(int i) {
  3194.            TreeModel model = JTree.this.getModel();
  3195.            if (model != null) {
  3196.                if (i == 0) {
  3197.                    Object[] objPath = {model.getRoot()};
  3198.                    TreePath path = new TreePath(objPath);
  3199.                    JTree.this.addSelectionPath(path);
  3200.                 }
  3201.             }
  3202.         }
  3203.  
  3204.         /**
  3205.          * Removes the specified selected item in the object from the object's
  3206.          * selection.  If the specified item isn't currently selected, this
  3207.          * method has no effect.
  3208.          *
  3209.          * @param i the zero-based index of selectable items
  3210.          */
  3211.         public void removeAccessibleSelection(int i) {
  3212.         TreeModel model = JTree.this.getModel();
  3213.         if (model != null) {
  3214.                 if (i == 0) {
  3215.                     Object[] objPath = {model.getRoot()};
  3216.                     TreePath path = new TreePath(objPath);
  3217.                     JTree.this.removeSelectionPath(path);
  3218.                 }
  3219.             }
  3220.         }
  3221.  
  3222.         /**
  3223.          * Clears the selection in the object, so that nothing in the
  3224.          * object is selected.
  3225.          */
  3226.         public void clearAccessibleSelection() {
  3227.             int childCount = getAccessibleChildrenCount();
  3228.             for (int i = 0; i < childCount; i++) {
  3229.                 removeAccessibleSelection(i);
  3230.             }
  3231.         }
  3232.  
  3233.         /**
  3234.          * Causes every selected item in the object to be selected
  3235.          * if the object supports multiple selections.
  3236.          */
  3237.         public void selectAllAccessibleSelection() {
  3238.             TreeModel model = JTree.this.getModel();
  3239.             if (model != null) {
  3240.                 Object[] objPath = {model.getRoot()};
  3241.                 TreePath path = new TreePath(objPath);
  3242.                 JTree.this.addSelectionPath(path);
  3243.             }
  3244.         }
  3245.  
  3246.         /**
  3247.          *
  3248.          */
  3249.         protected class AccessibleJTreeNode extends AccessibleContext
  3250.             implements Accessible, AccessibleComponent, AccessibleSelection, 
  3251.             AccessibleAction {
  3252.  
  3253.             private JTree tree = null;
  3254.             private TreeModel treeModel = null;
  3255.             private Object obj = null;
  3256.             private Object objParent = null;
  3257.             private TreePath path = null;
  3258.             private Accessible accessibleParent = null;
  3259.             private int index = -1;
  3260.             private boolean isLeaf = false;
  3261.  
  3262.             /**
  3263.              *  Constructs an AccessibleJTreeNode
  3264.              */
  3265.             public AccessibleJTreeNode(JTree t, TreePath p, Accessible ap) {
  3266.                 tree = t;
  3267.                 path = p;
  3268.                 accessibleParent = ap;
  3269.                 treeModel = t.getModel();
  3270.                 obj = p.getLastPathComponent();
  3271.                 Object[] objPath = p.getPath();
  3272.                 if (objPath.length > 1) {
  3273.                     objParent = objPath[objPath.length-2];
  3274.                     if (treeModel != null) {
  3275.                         index = treeModel.getIndexOfChild(objParent, obj);
  3276.                     }
  3277.                     Object[] objParentPath = new Object[objPath.length-1];
  3278.                     java.lang.System.arraycopy(objPath, 0, objParentPath, 0, objPath.length-1);
  3279.                     TreePath parentPath = new TreePath(objParentPath);
  3280.                     this.setAccessibleParent(accessibleParent);
  3281.                 } else {
  3282.                     if (treeModel != null) {
  3283.                         index = treeModel.getIndexOfChild(treeModel.getRoot(), obj);
  3284.                         this.setAccessibleParent(tree);
  3285.                     }
  3286.                 }
  3287.                 if (treeModel != null) {
  3288.                     isLeaf = treeModel.isLeaf(obj);
  3289.                 }
  3290.             }
  3291.  
  3292.             private TreePath getChildTreePath(int i) {
  3293.                 // Tree nodes can't be so complex that they have
  3294.                 // two sets of children -> we're ignoring that case
  3295.                 if (i < 0 || i >= getAccessibleChildrenCount()) {
  3296.                     return null;
  3297.                 } else {
  3298.                     Object childObj = treeModel.getChild(obj, i);
  3299.                     Object[] objPath = path.getPath();
  3300.                     Object[] objChildPath = new Object[objPath.length+1];
  3301.                     java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);
  3302.                     objChildPath[objChildPath.length-1] = childObj;
  3303.                     return new TreePath(objChildPath);
  3304.                 }
  3305.             }
  3306.  
  3307.             /**
  3308.              * Get the AccessibleContext associated with this tree node
  3309.              *
  3310.              * @return the AccessibleContext of this JComponent
  3311.              */
  3312.             public AccessibleContext getAccessibleContext() {
  3313.                 return this;
  3314.             }
  3315.  
  3316.             private AccessibleContext getCurrentAccessibleContext() {
  3317.                 Component c = getCurrentComponent();
  3318.                 if (c instanceof Accessible) {
  3319.                     return (((Accessible) c).getAccessibleContext());
  3320.                 } else {
  3321.                     return null;
  3322.                 }
  3323.             }
  3324.  
  3325.             private Component getCurrentComponent() {
  3326.                 // is the object visible?
  3327.                 // if so, get row, selected, focus & leaf state, 
  3328.                 // and then get the renderer component and return it
  3329.                 if (tree.isVisible(path)) {
  3330.                     TreeCellRenderer r = tree.getCellRenderer();
  3331.             if (r == null) {
  3332.             return null;
  3333.             }
  3334.                     TreeUI ui = tree.getUI();
  3335.                     if (ui != null) {
  3336.                         int row = ui.getRowForPath(JTree.this, path);
  3337.                         boolean selected = tree.isPathSelected(path);
  3338.                         boolean expanded = tree.isExpanded(path);
  3339.                         boolean hasFocus = false; // how to tell?? -PK
  3340.                         return r.getTreeCellRendererComponent(tree, obj, 
  3341.                             selected, expanded, isLeaf, row, hasFocus);
  3342.                     }
  3343.                 } 
  3344.                 return null;
  3345.             }
  3346.  
  3347.         // AccessibleContext methods
  3348.     
  3349.              /**
  3350.               * Get the accessible name of this object.
  3351.               *
  3352.               * @return the localized name of the object; null if this 
  3353.               * object does not have a name
  3354.               */
  3355.              public String getAccessibleName() {
  3356.                 AccessibleContext ac = getCurrentAccessibleContext();
  3357.                 if (ac != null) {
  3358.                     String name = ac.getAccessibleName();
  3359.                     if ((name != null) && (name != "")) {
  3360.                         return ac.getAccessibleName();
  3361.                     } else {
  3362.                         return null;
  3363.                     }
  3364.                 }
  3365.                 if ((accessibleName != null) && (accessibleName != "")) {
  3366.                     return accessibleName;
  3367.                 } else {
  3368.                     return null;
  3369.                 }
  3370.             }
  3371.     
  3372.             /**
  3373.              * Set the localized accessible name of this object.
  3374.              *
  3375.              * @param s the new localized name of the object.
  3376.              */
  3377.             public void setAccessibleName(String s) {
  3378.                 AccessibleContext ac = getCurrentAccessibleContext();
  3379.                 if (ac != null) {
  3380.                     ac.setAccessibleName(s);
  3381.                 } else {
  3382.                     super.setAccessibleName(s);
  3383.                 }
  3384.             }
  3385.     
  3386.             //
  3387.             // *** should check toolip text for desc. (needs MouseEvent)
  3388.             //
  3389.             /**
  3390.              * Get the accessible description of this object.
  3391.              *
  3392.              * @return the localized description of the object; null if 
  3393.              * this object does not have a description
  3394.              */
  3395.             public String getAccessibleDescription() {
  3396.                 AccessibleContext ac = getCurrentAccessibleContext();
  3397.                 if (ac != null) {
  3398.                     return ac.getAccessibleDescription();
  3399.                 } else {
  3400.                     return super.getAccessibleDescription();
  3401.                 }
  3402.             }
  3403.     
  3404.             /**
  3405.              * Set the accessible description of this object.
  3406.              *
  3407.              * @param s the new localized description of the object
  3408.              */
  3409.             public void setAccessibleDescription(String s) {
  3410.                 AccessibleContext ac = getCurrentAccessibleContext();
  3411.                 if (ac != null) {
  3412.                     ac.setAccessibleDescription(s);
  3413.                 } else {
  3414.                     super.setAccessibleDescription(s);
  3415.                 }
  3416.             }
  3417.     
  3418.             /**
  3419.              * Get the role of this object.
  3420.              *
  3421.              * @return an instance of AccessibleRole describing the role of the object
  3422.              * @see AccessibleRole
  3423.              */
  3424.             public AccessibleRole getAccessibleRole() {
  3425.                 AccessibleContext ac = getCurrentAccessibleContext();
  3426.                 if (ac != null) {
  3427.                     return ac.getAccessibleRole();
  3428.                 } else {
  3429.                     return AccessibleRole.UNKNOWN;
  3430.                 }
  3431.             }
  3432.     
  3433.             /**
  3434.              * Get the state set of this object.
  3435.              *
  3436.              * @return an instance of AccessibleStateSet containing the 
  3437.              * current state set of the object
  3438.              * @see AccessibleState
  3439.              */
  3440.             public AccessibleStateSet getAccessibleStateSet() {
  3441.                 AccessibleContext ac = getCurrentAccessibleContext();
  3442.                 AccessibleStateSet states;
  3443.         int row = tree.getUI().getRowForPath(tree,path);
  3444.         int lsr = tree.getLeadSelectionRow();
  3445.                 if (ac != null) {
  3446.                     states = ac.getAccessibleStateSet();
  3447.                 } else {
  3448.                     states = new AccessibleStateSet();
  3449.                 }
  3450.                 // need to test here, 'cause the underlying component 
  3451.                 // is a cellRenderer, which is never showing...
  3452.                 if (isShowing()) {
  3453.                     states.add(AccessibleState.SHOWING);
  3454.                 } else if (states.contains(AccessibleState.SHOWING)) {
  3455.                     states.remove(AccessibleState.SHOWING);
  3456.                 }
  3457.                 if (isVisible()) {
  3458.                     states.add(AccessibleState.VISIBLE);
  3459.                 } else if (states.contains(AccessibleState.VISIBLE)) {
  3460.                     states.remove(AccessibleState.VISIBLE);
  3461.                 }
  3462.                 if (tree.isPathSelected(path)){
  3463.                     states.add(AccessibleState.SELECTED);
  3464.                 }
  3465.         if (lsr == row) {
  3466.                     states.add(AccessibleState.ACTIVE);
  3467.                 }
  3468.                 if (!isLeaf) {
  3469.                     states.add(AccessibleState.EXPANDABLE);
  3470.                 }
  3471.                 if (tree.isExpanded(path)) {
  3472.                     states.add(AccessibleState.EXPANDED);
  3473.                 } else {
  3474.                     states.add(AccessibleState.COLLAPSED);
  3475.                 }
  3476.                 if (tree.isEditable()) {
  3477.                     states.add(AccessibleState.EDITABLE);
  3478.                 }
  3479.                 return states;
  3480.             }
  3481.     
  3482.             /**
  3483.              * Get the Accessible parent of this object.
  3484.              *
  3485.              * @return the Accessible parent of this object; null if this
  3486.              * object does not have an Accessible parent
  3487.              */
  3488.             public Accessible getAccessibleParent() {
  3489.                 return accessibleParent;
  3490.             }
  3491.     
  3492.             /**
  3493.              * Get the index of this object in its accessible parent. 
  3494.              *
  3495.              * @return the index of this object in its parent; -1 if this 
  3496.              * object does not have an accessible parent.
  3497.              * @see #getAccessibleParent
  3498.              */
  3499.             public int getAccessibleIndexInParent() {
  3500.                 return index;
  3501.             }
  3502.     
  3503.             /**
  3504.              * Returns the number of accessible children in the object.
  3505.              *
  3506.              * @return the number of accessible children in the object.
  3507.              */
  3508.             public int getAccessibleChildrenCount() {
  3509.                 // Tree nodes can't be so complex that they have 
  3510.                 // two sets of children -> we're ignoring that case
  3511.                 return treeModel.getChildCount(obj);
  3512.             }
  3513.     
  3514.             /**
  3515.              * Return the specified Accessible child of the object.
  3516.              *
  3517.              * @param i zero-based index of child
  3518.              * @return the Accessible child of the object
  3519.              */
  3520.             public Accessible getAccessibleChild(int i) {
  3521.                 // Tree nodes can't be so complex that they have 
  3522.                 // two sets of children -> we're ignoring that case
  3523.                 if (i < 0 || i >= getAccessibleChildrenCount()) {
  3524.                     return null;
  3525.                 } else {
  3526.                     Object childObj = treeModel.getChild(obj, i);
  3527.                     Object[] objPath = path.getPath();
  3528.                     Object[] objChildPath = new Object[objPath.length+1];
  3529.                     java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);
  3530.                     objChildPath[objChildPath.length-1] = childObj;
  3531.                     TreePath childPath = new TreePath(objChildPath);
  3532.                     return new AccessibleJTreeNode(JTree.this, childPath, this);
  3533.                 }
  3534.             }
  3535.     
  3536.             /** 
  3537.              * Gets the locale of the component. If the component does not have a 
  3538.              * locale, then the locale of its parent is returned.  
  3539.              *
  3540.              * @return This component's locale. If this component does not have a locale, the locale of its parent is returned.
  3541.              * @exception IllegalComponentStateException 
  3542.              * If the Component does not have its own locale and has not yet been added to a containment hierarchy such that the locale can be
  3543.              * determined from the containing parent. 
  3544.              * @see setLocale
  3545.              */
  3546.             public Locale getLocale() {
  3547.                 AccessibleContext ac = getCurrentAccessibleContext();
  3548.                 if (ac != null) {
  3549.                     return ac.getLocale();
  3550.                 } else {
  3551.                     return tree.getLocale();
  3552.                 }
  3553.             }
  3554.     
  3555.             /**
  3556.              * Add a PropertyChangeListener to the listener list.
  3557.              * The listener is registered for all properties.
  3558.              *
  3559.              * @param listener  The PropertyChangeListener to be added
  3560.              */
  3561.             public void addPropertyChangeListener(PropertyChangeListener l) {
  3562.                 AccessibleContext ac = getCurrentAccessibleContext();
  3563.                 if (ac != null) {
  3564.                     ac.addPropertyChangeListener(l);
  3565.                 } else {
  3566.                     super.addPropertyChangeListener(l);
  3567.                 }
  3568.             }
  3569.     
  3570.             /**
  3571.              * Remove a PropertyChangeListener from the listener list.
  3572.              * This removes a PropertyChangeListener that was registered
  3573.              * for all properties.
  3574.              *
  3575.              * @param listener  The PropertyChangeListener to be removed
  3576.              */
  3577.             public void removePropertyChangeListener(PropertyChangeListener l) {
  3578.                 AccessibleContext ac = getCurrentAccessibleContext();
  3579.                 if (ac != null) {
  3580.                     ac.removePropertyChangeListener(l);
  3581.                 } else {
  3582.                     super.removePropertyChangeListener(l);
  3583.                 }
  3584.             }
  3585.     
  3586.             /**
  3587.              * Get the AccessibleAction associated with this object if one
  3588.              * exists.  Otherwise return null.
  3589.              *
  3590.              * @return the AccessibleAction, or null
  3591.              */
  3592.             public AccessibleAction getAccessibleAction() {
  3593.                 return this;
  3594.             }
  3595.  
  3596.             /**
  3597.              * Get the AccessibleComponent associated with this tree node
  3598.              * NOTE: if the node is not displayed (either scrolled off of
  3599.              * the screen, or not expanded), this will return null
  3600.              *
  3601.              * @return the AccessibleComponent of this tree node
  3602.              */
  3603.             public AccessibleComponent getAccessibleComponent() {
  3604.                 return this; // to override getBounds()
  3605.             }
  3606.  
  3607.             /**
  3608.              * Get the AccessibleSelection associated with this object if one
  3609.              * exists.  Otherwise return null.
  3610.              *
  3611.              * @return the AccessibleSelection, or null
  3612.              */
  3613.             public AccessibleSelection getAccessibleSelection() {
  3614.                 AccessibleContext ac = getCurrentAccessibleContext();
  3615.                 if (ac != null && isLeaf) {
  3616.                     return getCurrentAccessibleContext().getAccessibleSelection();
  3617.                 } else {
  3618.                     return this;
  3619.                 }
  3620.             }
  3621.  
  3622.             /**
  3623.              * Get the AccessibleText associated with this object if one
  3624.              * exists.  Otherwise return null.
  3625.              *
  3626.              * @return the AccessibleText, or null
  3627.              */
  3628.             public AccessibleText getAccessibleText() {
  3629.                 AccessibleContext ac = getCurrentAccessibleContext();
  3630.                 if (ac != null) {
  3631.                     return getCurrentAccessibleContext().getAccessibleText();
  3632.                 } else {
  3633.                     return null;
  3634.                 }
  3635.             }
  3636.  
  3637.             /**
  3638.              * Get the AccessibleValue associated with this object if one
  3639.              * exists.  Otherwise return null.
  3640.              *
  3641.              * @return the AccessibleValue, or null
  3642.              */
  3643.             public AccessibleValue getAccessibleValue() {
  3644.                 AccessibleContext ac = getCurrentAccessibleContext();
  3645.                 if (ac != null) {
  3646.                     return getCurrentAccessibleContext().getAccessibleValue();
  3647.                 } else {
  3648.                     return null;
  3649.                 }
  3650.             }
  3651.  
  3652.  
  3653.         // AccessibleComponent methods
  3654.     
  3655.             /**
  3656.              * Get the background color of this object.
  3657.              *
  3658.              * @return the background color, if supported, of the object; 
  3659.              * otherwise, null
  3660.              */
  3661.             public Color getBackground() {
  3662.                 AccessibleContext ac = getCurrentAccessibleContext();
  3663.                 if (ac instanceof AccessibleComponent) {
  3664.                     return ((AccessibleComponent) ac).getBackground();
  3665.                 } else {
  3666.                     Component c = getCurrentComponent();
  3667.                     if (c != null) {
  3668.                         return c.getBackground();
  3669.                     } else {
  3670.                         return null;
  3671.                     }
  3672.                 }
  3673.             }
  3674.     
  3675.             /**
  3676.              * Set the background color of this object.
  3677.              *
  3678.              * @param c the new Color for the background
  3679.              */
  3680.             public void setBackground(Color c) {
  3681.                 AccessibleContext ac = getCurrentAccessibleContext();
  3682.                 if (ac instanceof AccessibleComponent) {
  3683.                     ((AccessibleComponent) ac).setBackground(c);
  3684.                 } else {
  3685.                     Component cp = getCurrentComponent();
  3686.                     if (cp != null) {
  3687.                         cp.setBackground(c);
  3688.                     }
  3689.                 }
  3690.             }
  3691.     
  3692.         
  3693.             /**
  3694.              * Get the foreground color of this object.
  3695.              *
  3696.              * @return the foreground color, if supported, of the object; 
  3697.              * otherwise, null
  3698.              */
  3699.             public Color getForeground() {
  3700.                 AccessibleContext ac = getCurrentAccessibleContext();
  3701.                 if (ac instanceof AccessibleComponent) {
  3702.                     return ((AccessibleComponent) ac).getForeground();
  3703.                 } else {
  3704.                     Component c = getCurrentComponent();
  3705.                     if (c != null) {
  3706.                         return c.getForeground();
  3707.                     } else {
  3708.                         return null;
  3709.                     }
  3710.                 }
  3711.             }
  3712.     
  3713.             public void setForeground(Color c) {
  3714.                 AccessibleContext ac = getCurrentAccessibleContext();
  3715.                 if (ac instanceof AccessibleComponent) {
  3716.                     ((AccessibleComponent) ac).setForeground(c);
  3717.                 } else {
  3718.                     Component cp = getCurrentComponent();
  3719.                     if (cp != null) {
  3720.                         cp.setForeground(c);
  3721.                     }
  3722.                 }
  3723.             }
  3724.     
  3725.             public Cursor getCursor() {
  3726.                 AccessibleContext ac = getCurrentAccessibleContext();
  3727.                 if (ac instanceof AccessibleComponent) {
  3728.                     return ((AccessibleComponent) ac).getCursor();
  3729.                 } else {
  3730.                     Component c = getCurrentComponent();
  3731.                     if (c != null) {
  3732.                         return c.getCursor();
  3733.                     } else {
  3734.                         Accessible ap = getAccessibleParent();
  3735.                         if (ap instanceof AccessibleComponent) {
  3736.                             return ((AccessibleComponent) ap).getCursor();
  3737.                         } else {
  3738.                             return null;
  3739.                         }
  3740.                     }
  3741.                 }
  3742.             }
  3743.     
  3744.             public void setCursor(Cursor c) {
  3745.                 AccessibleContext ac = getCurrentAccessibleContext();
  3746.                 if (ac instanceof AccessibleComponent) {
  3747.                     ((AccessibleComponent) ac).setCursor(c);
  3748.                 } else {
  3749.                     Component cp = getCurrentComponent();
  3750.                     if (cp != null) {
  3751.                         cp.setCursor(c);
  3752.                     }
  3753.                 }
  3754.             }
  3755.     
  3756.             public Font getFont() {
  3757.                 AccessibleContext ac = getCurrentAccessibleContext();
  3758.                 if (ac instanceof AccessibleComponent) {
  3759.                     return ((AccessibleComponent) ac).getFont();
  3760.                 } else {
  3761.                     Component c = getCurrentComponent();
  3762.                     if (c != null) {
  3763.                         return c.getFont();
  3764.                     } else {
  3765.                         return null;
  3766.                     }
  3767.                 }
  3768.             }
  3769.     
  3770.             public void setFont(Font f) {
  3771.                 AccessibleContext ac = getCurrentAccessibleContext();
  3772.                 if (ac instanceof AccessibleComponent) {
  3773.                     ((AccessibleComponent) ac).setFont(f);
  3774.                 } else {
  3775.                     Component c = getCurrentComponent();
  3776.                     if (c != null) {
  3777.                         c.setFont(f);
  3778.                     }
  3779.                 }
  3780.             }
  3781.     
  3782.             public FontMetrics getFontMetrics(Font f) {
  3783.                 AccessibleContext ac = getCurrentAccessibleContext();
  3784.                 if (ac instanceof AccessibleComponent) {
  3785.                     return ((AccessibleComponent) ac).getFontMetrics(f);
  3786.                 } else {
  3787.                     Component c = getCurrentComponent();
  3788.                     if (c != null) {
  3789.                         return c.getFontMetrics(f);
  3790.                     } else {
  3791.                         return null;
  3792.                     }
  3793.                 }
  3794.             }
  3795.     
  3796.             public boolean isEnabled() {
  3797.                 AccessibleContext ac = getCurrentAccessibleContext();
  3798.                 if (ac instanceof AccessibleComponent) {
  3799.                     return ((AccessibleComponent) ac).isEnabled();
  3800.                 } else {
  3801.                     Component c = getCurrentComponent();
  3802.                     if (c != null) {
  3803.                         return c.isEnabled();
  3804.                     } else {
  3805.                         return false;
  3806.                     }
  3807.                 }
  3808.             }
  3809.     
  3810.             public void setEnabled(boolean b) {
  3811.                 AccessibleContext ac = getCurrentAccessibleContext();
  3812.                 if (ac instanceof AccessibleComponent) {
  3813.                     ((AccessibleComponent) ac).setEnabled(b);
  3814.                 } else {
  3815.                     Component c = getCurrentComponent();
  3816.                     if (c != null) {
  3817.                         c.setEnabled(b);
  3818.                     }
  3819.                 }
  3820.             }
  3821.     
  3822.             public boolean isVisible() {
  3823.                 Rectangle pathBounds = tree.getPathBounds(path);
  3824.                 Rectangle parentBounds = tree.getVisibleRect();
  3825.                 if (pathBounds != null && parentBounds != null && 
  3826.                     parentBounds.intersects(pathBounds)) {
  3827.                     return true;
  3828.                 } else {
  3829.                     return false;
  3830.                 }
  3831.             }
  3832.     
  3833.             public void setVisible(boolean b) {
  3834.             }
  3835.     
  3836.             public boolean isShowing() {
  3837.                 return (tree.isShowing() && isVisible());
  3838.             }
  3839.     
  3840.             public boolean contains(Point p) {
  3841.                 AccessibleContext ac = getCurrentAccessibleContext();
  3842.                 if (ac instanceof AccessibleComponent) {
  3843.                     Rectangle r = ((AccessibleComponent) ac).getBounds();
  3844.                     return r.contains(p);
  3845.                 } else {
  3846.                     Component c = getCurrentComponent();
  3847.                     if (c != null) {
  3848.                         Rectangle r = c.getBounds();
  3849.                         return r.contains(p);
  3850.                     } else {
  3851.                         return getBounds().contains(p);
  3852.                     }
  3853.                 }
  3854.             }
  3855.     
  3856.             public Point getLocationOnScreen() {
  3857.                 if (tree != null) {
  3858.                     Point parentLocation = tree.getLocationOnScreen();
  3859.                     Point componentLocation = getLocation();
  3860.                     componentLocation.translate(parentLocation.x, parentLocation.y);
  3861.                     return componentLocation;
  3862.                 } else {
  3863.                     return null;
  3864.                 }
  3865.             }
  3866.     
  3867.             protected Point getLocationInJTree() {
  3868.                 Rectangle r = tree.getPathBounds(path);
  3869.                 if (r != null) {
  3870.                     return r.getLocation();
  3871.                 } else {
  3872.                     return null;
  3873.                 }
  3874.             }
  3875.  
  3876.             public Point getLocation() {
  3877.                 Rectangle r = getBounds();
  3878.                 if (r != null) {
  3879.                     return r.getLocation();
  3880.                 } else {
  3881.                     return null;
  3882.                 }
  3883.             }
  3884.     
  3885.             public void setLocation(Point p) {
  3886.             }
  3887.                 
  3888.             public Rectangle getBounds() {
  3889.                 Rectangle r = tree.getPathBounds(path);
  3890.                 Accessible parent = getAccessibleParent();
  3891.                 if (parent != null) {
  3892.                     if (parent instanceof AccessibleJTreeNode) {
  3893.                         Point parentLoc = ((AccessibleJTreeNode) parent).getLocationInJTree();
  3894.                         if (parentLoc != null && r != null) {
  3895.                             r.translate(-parentLoc.x, -parentLoc.y);
  3896.                         } else {
  3897.                             return null;        // not visible!
  3898.                         }
  3899.                     } 
  3900.                 }
  3901.                 return r;
  3902.             }
  3903.     
  3904.             public void setBounds(Rectangle r) {
  3905.                 AccessibleContext ac = getCurrentAccessibleContext();
  3906.                 if (ac instanceof AccessibleComponent) {
  3907.                     ((AccessibleComponent) ac).setBounds(r);
  3908.                 } else {
  3909.                     Component c = getCurrentComponent();
  3910.                     if (c != null) {
  3911.                         c.setBounds(r);
  3912.                     }
  3913.                 }
  3914.             }
  3915.     
  3916.             public Dimension getSize() {
  3917.                 return getBounds().getSize();
  3918.             }
  3919.     
  3920.             public void setSize (Dimension d) {
  3921.                 AccessibleContext ac = getCurrentAccessibleContext();
  3922.                 if (ac instanceof AccessibleComponent) {
  3923.                     ((AccessibleComponent) ac).setSize(d);
  3924.                 } else {
  3925.                     Component c = getCurrentComponent();
  3926.                     if (c != null) {
  3927.                         c.setSize(d);
  3928.                     }
  3929.                 }
  3930.             }
  3931.     
  3932.             public Accessible getAccessibleAt(Point p) {
  3933.                 AccessibleContext ac = getCurrentAccessibleContext();
  3934.                 if (ac instanceof AccessibleComponent) {
  3935.                     return ((AccessibleComponent) ac).getAccessibleAt(p);
  3936.                 } else {
  3937.                     return null;
  3938.                 }
  3939.             }
  3940.     
  3941.             public boolean isFocusTraversable() {
  3942.                 AccessibleContext ac = getCurrentAccessibleContext();
  3943.                 if (ac instanceof AccessibleComponent) {
  3944.                     return ((AccessibleComponent) ac).isFocusTraversable();
  3945.                 } else {
  3946.                     Component c = getCurrentComponent();
  3947.                     if (c != null) {
  3948.                         return c.isFocusTraversable();
  3949.                     } else {
  3950.                         return false;
  3951.                     }
  3952.                 }
  3953.             }
  3954.     
  3955.             public void requestFocus() {
  3956.                 AccessibleContext ac = getCurrentAccessibleContext();
  3957.                 if (ac instanceof AccessibleComponent) {
  3958.                     ((AccessibleComponent) ac).requestFocus();
  3959.                 } else {
  3960.                     Component c = getCurrentComponent();
  3961.                     if (c != null) {
  3962.                         c.requestFocus();
  3963.                     }
  3964.                 }
  3965.             }
  3966.     
  3967.             public void addFocusListener(FocusListener l) {
  3968.                 AccessibleContext ac = getCurrentAccessibleContext();
  3969.                 if (ac instanceof AccessibleComponent) {
  3970.                     ((AccessibleComponent) ac).addFocusListener(l);
  3971.                 } else {
  3972.                     Component c = getCurrentComponent();
  3973.                     if (c != null) {
  3974.                         c.addFocusListener(l);
  3975.                     }
  3976.                 }
  3977.             }
  3978.     
  3979.             public void removeFocusListener(FocusListener l) {
  3980.                 AccessibleContext ac = getCurrentAccessibleContext();
  3981.                 if (ac instanceof AccessibleComponent) {
  3982.                     ((AccessibleComponent) ac).removeFocusListener(l);
  3983.                 } else {
  3984.                     Component c = getCurrentComponent();
  3985.                     if (c != null) {
  3986.                         c.removeFocusListener(l);
  3987.                     }
  3988.                 }
  3989.             }
  3990.  
  3991.         // AccessibleSelection methods
  3992.  
  3993.             /**
  3994.              * Returns the number of items currently selected.
  3995.              * If no items are selected, the return value will be 0.
  3996.              *
  3997.              * @return the number of items currently selected.
  3998.              */
  3999.             public int getAccessibleSelectionCount() {
  4000.                 int count = 0;
  4001.                 int childCount = getAccessibleChildrenCount();
  4002.                 for (int i = 0; i < childCount; i++) {
  4003.                     TreePath childPath = getChildTreePath(i);
  4004.                     if (tree.isPathSelected(childPath)) {
  4005.                        count++;
  4006.                     }
  4007.                 } 
  4008.                 return count;
  4009.             }
  4010.  
  4011.             /**
  4012.              * Returns an Accessible representing the specified selected item
  4013.              * in the object.  If there isn't a selection, or there are 
  4014.              * fewer items selcted than the integer passed in, the return
  4015.              * value will be null.
  4016.              *
  4017.              * @param i the zero-based index of selected items
  4018.              * @return an Accessible containing the selected item
  4019.              */
  4020.             public Accessible getAccessibleSelection(int i) {
  4021.                 int childCount = getAccessibleChildrenCount();
  4022.                 if (i < 0 || i >= childCount) {
  4023.                     return null;        // out of range
  4024.                 }
  4025.                 int count = 0;
  4026.                 for (int j = 0; j < childCount && i >= count; j++) {
  4027.                     TreePath childPath = getChildTreePath(j);
  4028.                     if (tree.isPathSelected(childPath)) { 
  4029.                         if (count == i) {
  4030.                             return new AccessibleJTreeNode(tree, childPath, this);
  4031.                         } else {
  4032.                             count++;
  4033.                         }
  4034.                     }
  4035.                 }
  4036.                 return null;
  4037.             }
  4038.  
  4039.             /**
  4040.              * Returns true if the current child of this object is selected.
  4041.              *
  4042.              * @param i the zero-based index of the child in this Accessible 
  4043.              * object.
  4044.              * @see AccessibleContext#getAccessibleChild
  4045.              */
  4046.             public boolean isAccessibleChildSelected(int i) {
  4047.                 int childCount = getAccessibleChildrenCount();
  4048.                 if (i < 0 || i >= childCount) {
  4049.                     return false;       // out of range
  4050.                 } else {
  4051.                     TreePath childPath = getChildTreePath(i);
  4052.                     return tree.isPathSelected(childPath);
  4053.                 }
  4054.             }
  4055.  
  4056.             /**
  4057.              * Adds the specified selected item in the object to the object's
  4058.              * selection.  If the object supports multiple selections,
  4059.              * the specified item is added to any existing selection, otherwise
  4060.              * it replaces any existing selection in the object.  If the
  4061.              * specified item is already selected, this method has no effect.
  4062.              *
  4063.              * @param i the zero-based index of selectable items
  4064.              */
  4065.             public void addAccessibleSelection(int i) {
  4066.                TreeModel model = JTree.this.getModel();
  4067.                if (model != null) {
  4068.                    if (i >= 0 && i < getAccessibleChildrenCount()) {
  4069.                        TreePath path = getChildTreePath(i);
  4070.                        JTree.this.addSelectionPath(path);
  4071.                     }
  4072.                 }
  4073.             }
  4074.  
  4075.             /**
  4076.              * Removes the specified selected item in the object from the 
  4077.              * object's
  4078.              * selection.  If the specified item isn't currently selected, this
  4079.              * method has no effect.
  4080.              *
  4081.              * @param i the zero-based index of selectable items
  4082.              */
  4083.             public void removeAccessibleSelection(int i) {
  4084.                TreeModel model = JTree.this.getModel();
  4085.                if (model != null) {
  4086.                    if (i >= 0 && i < getAccessibleChildrenCount()) {
  4087.                        TreePath path = getChildTreePath(i);
  4088.                        JTree.this.removeSelectionPath(path);
  4089.                     }
  4090.                 }
  4091.             }
  4092.  
  4093.             /**
  4094.              * Clears the selection in the object, so that nothing in the
  4095.              * object is selected.
  4096.              */
  4097.             public void clearAccessibleSelection() {
  4098.                 int childCount = getAccessibleChildrenCount();
  4099.                 for (int i = 0; i < childCount; i++) {
  4100.                     removeAccessibleSelection(i);
  4101.                 }
  4102.             }
  4103.  
  4104.             /**
  4105.              * Causes every selected item in the object to be selected
  4106.              * if the object supports multiple selections.
  4107.              */
  4108.             public void selectAllAccessibleSelection() {
  4109.                TreeModel model = JTree.this.getModel();
  4110.                if (model != null) {
  4111.                    int childCount = getAccessibleChildrenCount();
  4112.                    TreePath path;
  4113.                    for (int i = 0; i < childCount; i++) {
  4114.                        path = getChildTreePath(i);
  4115.                        JTree.this.addSelectionPath(path);
  4116.                    }
  4117.                 }
  4118.             }
  4119.  
  4120.         // AccessibleAction methods
  4121.  
  4122.             /**
  4123.              * Returns the number of accessible actions available in this 
  4124.              * tree node.  If this node is not a leaf, there is at least 
  4125.              * one action (toggle expand), in addition to any available
  4126.              * on the object behind the TreeCellRenderer.
  4127.              *
  4128.              * @return the number of Actions in this object
  4129.              */
  4130.             public int getAccessibleActionCount() {
  4131.                 AccessibleContext ac = getCurrentAccessibleContext();
  4132.                 if (ac != null) {
  4133.                     AccessibleAction aa = ac.getAccessibleAction();
  4134.                     if (aa != null) {
  4135.                         return (aa.getAccessibleActionCount() + (isLeaf ? 0 : 1));
  4136.                     }
  4137.                 }
  4138.                 return isLeaf ? 0 : 1;
  4139.             }
  4140.  
  4141.             /**
  4142.              * Return a description of the specified action of the tree node.
  4143.              * If this node is not a leaf, there is at least one action
  4144.              * description (toggle expand), in addition to any available
  4145.              * on the object behind the TreeCellRenderer.
  4146.              *
  4147.              * @param i zero-based index of the actions
  4148.              * @return a description of the action
  4149.              */
  4150.             public String getAccessibleActionDescription(int i) {
  4151.                 if (i < 0 || i >= getAccessibleActionCount()) {
  4152.                     return null;
  4153.                 }
  4154.                 AccessibleContext ac = getCurrentAccessibleContext();
  4155.                 if (i == 0) {
  4156.                     return "toggle expand";
  4157.                 } else if (ac != null) {
  4158.                     AccessibleAction aa = ac.getAccessibleAction();
  4159.                     if (aa != null) {
  4160.                         return aa.getAccessibleActionDescription(i - 1);
  4161.                     }
  4162.                 }
  4163.                 return null;
  4164.             }
  4165.  
  4166.             /**
  4167.              * Perform the specified Action on the tree node.  If this node
  4168.              * is not a leaf, there is at least one action which can be
  4169.              * done (toggle expand), in addition to any available on the 
  4170.              * object behind the TreeCellRenderer.
  4171.              *
  4172.              * @param i zero-based index of actions
  4173.              * @return true if the the action was performed; else false.
  4174.              */
  4175.             public boolean doAccessibleAction(int i) {
  4176.                 if (i < 0 || i >= getAccessibleActionCount()) {
  4177.                     return false;
  4178.                 }
  4179.                 AccessibleContext ac = getCurrentAccessibleContext();
  4180.                 if (i == 0) {
  4181.                     if (JTree.this.isExpanded(path)) {
  4182.                         JTree.this.collapsePath(path);
  4183.                     } else {
  4184.                         JTree.this.expandPath(path);
  4185.                     }
  4186.                     return true;
  4187.                 } else if (ac != null) {
  4188.                     AccessibleAction aa = ac.getAccessibleAction();
  4189.                     if (aa != null) {
  4190.                         return aa.doAccessibleAction(i - 1);
  4191.                     }
  4192.                 }
  4193.                 return false;
  4194.             }
  4195.  
  4196.         } // inner class AccessibleJTreeNode
  4197.  
  4198.     }  // inner class AccessibleJTree
  4199.  
  4200. } // End of class JTree
  4201.  
  4202.